mootools_使用MooTools和Node.js的ServerSide JavaScript

mootools

MooTools and Node.js

This post was authored by Christoph Pojer. To learn more about Christoph, click here.

这篇文章是由克里斯托弗·波耶 ( Christoph Pojer )撰写的。 要了解有关Christoph的更多信息, 请单击此处

This blog post is intended to provide a starting point for ServerSide JavaScript (SSJS) development with MooTools. It is focused on Node.js (http://nodejs.org) and tries to explain the main concepts and differences from client side development. It is solely based on my current experience, my current work, and the best practices I have defined for myself so far - though most of this has been heavily influenced by people from other people of the MooTools team.

这篇博客文章旨在为MooTools开发ServerSide JavaScript(SSJS)提供一个起点。 它专注于Node.js( http://nodejs.org ),并试图解释主要概念以及与客户端开发之间的区别。 它仅基于我目前的经验,当前的工作以及到目前为止为我自己定义的最佳实践-尽管其中大多数受到了MooTools团队其他人的严重影响。

如何设置Node.js (How to Setup Node.js)

It can't get any easier.

再简单不过了。

MooTools和SSJS的现状 (Current State of MooTools and SSJS)

Our current releases, MooTools Core 1.2 and 1.3beta2, do not work out of the box with Node.js. Node.js, as well as other serverside JavaScript implementations have adopted the CommonJS standard which includes a module system. Every module you create can export objects via the "exports" object. You can include a file by using "require('path/to/module')" which gives you access to the module's exported variables:

当前的MooTools Core 1.2和1.3beta2版本无法与Node.js一起使用。 Node.js以及其他服务器端JavaScript实现都采用了CommonJS标准,其中包括模块系统。 您创建的每个模块都可以通过“导出”对象导出对象。 您可以使用“ require('path / to / module')”包含一个文件,该文件使您可以访问模块的导出变量:

math.js (math.js)


exports.add = function(a, b){
	return a + b;
};


myApplication.js (myApplication.js)


var math = require('./math');

var sys = require('sys'); // System module

sys.puts(math.add(13, 37)); // Outputs "50"


You can execute this script via "node myApplication.js" on the command line.

您可以通过命令行上的“ node myApplication.js”执行此脚本。

You can find more information about this on the CommonJS Wiki: http://wiki.commonjs.org/wiki/Modules/1.1.

您可以在CommonJS Wiki上找到有关此的更多信息: http ://wiki.commonjs.org/wiki/Modules/1.1。

The key difference between the module system as specified in CommonJS and normal client side script-tags is that they do not share the same (global) scope. This means that creating a variable via "var foo" in a module does not automatically make it available on the global object. The global object on the client side is the "window"-object which is usually not available on the serverside. In Node.js the global object is called GLOBAL, whereas some other implementations simply use the name "global" or just reference it to "this" inside a module. This is not defined by CommonJS so every environment solves it in a different way.

CommonJS中指定的模块系统与普通客户端脚本标签之间的主要区别在于它们不共享相同的(全局)作用域。 这意味着在模块中通过“ var foo”创建变量不会自动使其在全局对象上可用。 客户端的全局对象是“窗口”对象,通常在服务器端不可用。 在Node.js中,全局对象称为GLOBAL,而其他一些实现仅使用名称“ global”或在模块内部将其引用为“ this”。 CommonJS没有定义它,因此每种环境都以不同的方式解决它。

While it is relatively easy to add support for modules in a JavaScript library that revolves around only one object, MooTools provides several global variables such as Class, Events, Type (Native) etc. In addition to that this new standard is very young and if we ever implement support for CommonJS directly into MooTools we want to define the best practices that we can recommend to our whole community.

尽管在仅围绕一个对象JavaScript库中添加对模块的支持相对容易,但MooTools提供了一些全局变量,例如Class,Events,Type(Native)等。此外,该新标准还很年轻,如果我们曾经直接在MooTools中实现对CommonJS的支持,我们希望定义可以推荐给整个社区的最佳实践。

Note: CommonJS is not actually a standard but more of a set of specifications that a serverside implementation of JavaScript can (or should) follow to unify the various environments and to make it possible to create modules that work on all platforms without any modifications.

注意:CommonJS实际上不是标准,而是服务器规范JavaScript可以(或应该)遵循的一组规范,以统一各种环境,并使创建无需修改即可在所有平台上工作的模块成为可能。

获取在Node.js上运行的MooTools (Get MooTools Running on Node.js)

Over the past couple of months some members of the MooTools team came up with various ways to make MooTools CommonJS compatible. I have now created a repository on GitHub that helps create a build version of MooTools. This is mostly based on work by @keeto and me. We are going to use the work-in-progress version of MooTools Core, which is a pre 1.3 version. If you don't have git installed or don't feel like entering some commands you can skip ahead to the next section and just download a pre-build version of MooTools: MooTools.js (based on this commit).

在过去的几个月中,MooTools团队的一些成员提出了各种使MooTools CommonJS兼容的方法。 我现在在GitHub上创建了一个存储库,该存储库有助于创建MooTools的构建版本。 这主要是基于我和@keeto的工作。 我们将使用MooTools Core的进行中版本,它是1.3之前的版本。 如果您没有安装git或不想输入某些命令,则可以跳到下一部分,而只需下载MooTools的预构建版本: MooTools.js (基于提交)。

获取MooTools 1.3wip(命令行) (Get MooTools 1.3wip (command line))


git clone git://github.com/cpojer/mootools-core.git


获取打包程序(需要安装php-cli) (Get Packager (requires php-cli to be installed))


git clone http://github.com/kamicane/packager.git


获取MooTools CommonJS加载程序 (Get the MooTools CommonJS Loader)


git clone git://github.com/cpojer/mootools-loader.git


建立自定义的MooTools版本 (Build a Custom MooTools Version)


cd packager # Switch into the Packager folder

./packager register /path/to/mootools-core
./packager register /path/to/mootools-loader

./packager build Loader/Prefix Core/Class Core/Class.Extras Loader/Loader -blocks 1.2compat > MooTools.js


You should see some output like this:

您应该看到类似以下的输出:


Build using: Core, Loader
Included Files/Components:
- Loader/Prefix: [Prefix]
- Core/Core: [Core, MooTools, Type, typeOf, instanceOf]
- Core/Array: [Array]
- Core/String: [String]
- Core/Function: [Function]
- Core/Number: [Number]
- Core/Class: [Class]
- Core/Class.Extras: [Class.Extras, Chain, Events, Options]
- Core/Object: [Object, Hash]
- Loader/Loader: [Loader]


and a file "MooTools.js" should have been created that is ready to be used.

并且应该已经准备好使用文件“ MooTools.js”。

在Node.js中使用MooTools (Use MooTools in Node.js)


require.paths.push('path/to/mootoolsjs/');

require('MooTools').apply(GLOBAL);

var sys = require('sys');

var MyClass = new Class({

	initialize: function(){
		sys.puts('It works!');
	}

});

new MyClass;


Run this, again with the "node" command, on the command line and you should see "It works!" as output.

在命令行上再次使用“ node”命令运行此命令,您应该看到“它有效!” 作为输出。

Please note that this is quite experimental, the functionality you will find is subject to change and might contain bugs. The above solution has so far only been tested on Node.js but it should work on other SSJS implementations too

请注意,这是实验性的,您会发现其功能可能会发生更改,并且可能包含错误。 到目前为止,上述解决方案仅在Node.js上进行了测试,但它也应该在其他SSJS实现上也可以使用

应用程序和模块之间的差异 (Difference Between Applications and Modules)

One thing that I want to highlight is that I'm convinced that modules should not create global variables. However, the above mentioned solution puts everything MooTools provides on the global scope. While it is reasonable to do this when you are developing an application and you have control over every aspect of it, I do not believe it is a good idea to do this when you create a module (plugin) that uses MooTools. This is why the solution I came up with has another way to work with it, consider the following example.

我要强调的一件事是,我坚信模块不应创建全局变量。 但是,上述解决方案将MooTools提供的所有功能都放在了全局范围内。 尽管在开发应用程序时可以做到这一点是合理的,并且可以控制它的各个方面,但是我不认为在创建使用MooTools的模块(插件)时这样做是个好主意。 这就是为什么我想出的解决方案还有另一种使用它的方法,请考虑以下示例。

MyPlugin.js (MyPlugin.js)


var Moo = require('MooTools'),
	Class = Moo.Class,
	Options = Moo.Options,
	typeOf = Moo.typeOf;

exports.MyPlugin = new Class({

	Implements: [Options],
	
	options: {
		name: ''
	},
	
	initialize: function(options){
		if (!options) options = {};

		if (typeOf(options.name) != 'string')
			throw new Error("Ohmy!");
		
		this.setOptions(options);
	}

});


MyApplication.js (MyApplication.js)


// Add path to MooTools module so every module can just require "MooTools" without specifying the exact path
require.paths.push('path/to/mootoolsjs/');

var MyPlugin = require('path/to/MyPlugin').MyPlugin;

new MyPlugin({name: 'Kid Rock'});

// We can still add all the MooTools objects to the global scope without breaking anything
require('MooTools').apply(GLOBAL);

new Class(..);


You can now share the MyPlugin-Class with other people and it will work for them even if they do not put the MooTools objects on the global scope.

现在,您可以与其他人共享MyPlugin-Class,即使他们没有将MooTools对象放在全局范围内,它也将对他们有用。

Note: MooTools still adds extensions to the native types, such as String, Array and Function even if you do not put it on the global scope. Executing "require('MooTools')" once makes all the extensions available in any scope. Note that, at least at the moment, all modules share the exact same datatypes; there are no sandboxed datatypes. If extending the native types in JavaScript does not align with your style of coding you should probably not use MooTools (or JavaScript, as it is a core feature of the language). One of the goals of the MooTools project is to provide a framework that feels natural and does not make a distinction between the core language and functionality of the library.

注意:即使您没有将MooTools放在全局范围内,它仍会向本机类型添加扩展,例如String,Array和Function。 一旦执行“ require('MooTools')”,所有扩展就可以在任何范围内使用。 请注意,至少目前,所有模块都共享完全相同的数据类型。 没有沙盒数据类型。 如果在JavaScript中扩展本机类型与您的编码风格不符,则可能不应使用MooTools(或JavaScript,因为它是该语言的核心功能)。 MooTools项目的目标之一是提供一种感觉自然且不会在库的核心语言和功能之间进行区分的框架。

为什么“事件”? 异步吧? (Why "evented"? Async, huh?)

JavaScript, as a language mostly used on the clientside, has strong asynchronous capabilities. This means that most of the time you define certain functionality in your application that gets executed when a user - a real person - interacts with the content of a website. You usually do this by adding listeners to certain events on DOM elements:

JavaScript作为一种主要在客户端使用的语言,具有强大的异步功能。 这意味着大多数情况下,您会在应用程序中定义某些功能,当用户(一个真实的人)与网站内容进行交互时,该功能就会执行。 通常,您可以通过向DOM元素上的某些事件添加侦听器来做到这一点:


myElement.addEvent('click', function(){
	// This function gets executed upon interaction
});


You call the addEvent method and add a function to it, the program flow continues normally and the function is called asynchronously whenever a user clicks on it. In any case, you do not want to wait with the execution of any other code until this event gets executed. You do not want the click event listener to block. This is the main design goal of Node.js: to be non-blocking for any I/O operations such as reading or writing a file, storing or retrieving data from a database etc. This means that most code you will write on the serverside passes around functions (callbacks, event listeners) that get executed at a later time (e.g. when results of an operation are ready). You can find a simple example right on the Node.js website: http://nodejs.org/

您调用addEvent方法并向其中添加一个函数,程序流程将正常继续,并且每当用户单击该函数时,都会异步调用该函数。 无论如何,您不希望在执行此事件之前等待其他任何代码的执行。 您不希望click事件监听器被阻止。 这是Node.js的主要设计目标:不阻塞任何I / O操作,例如读取或写入文件,存储或检索数据库中的数据等。这意味着您将在服务器端编写大多数代码传递函数(回调,事件侦听器),这些函数将在以后的时间(例如,准备好操作结果时)执行。 您可以在Node.js网站上找到一个简单的示例: http : //nodejs.org/

To give you a better understanding, this is some sample code of what user authentication could look like with MooTools:

为了让您更好地理解,这是一些使用MooTools进行用户身份验证的示例代码:


var Moo = require('MooTools'),
	Class = Moo.Class,
	Db = require('Database').getDatabase(),
	sha1 = require('Sha1');

exports.User = new Class({

	initialize: function(name){
  		this.name = name;
	},

	authenticate: function(password, callback){
		var user = this;
		Db.open(function(db){
			db.collection('users', function(err, collection){
				if (err) return callback(err);

				collection.findOne({name: user.name, password: sha1.hex(password)}, function(err, data){
					if (err) return callback(err);

					callback(null, data != null);
				});
			});
		});
	}

});


In your application you would now create a new instance of User and call the authenticate method with a callback like this

在您的应用程序中,您现在将创建一个新的User实例,并使用类似这样的回调调用authenticate方法


	var User = require('User');

	var sys = require('sys');

	var instance = new User('david');
	instance.authenticate('kidrock', function(err, result){
		if (err) return; // handle database error

		if (result) sys.puts('User authenticated');
		else sys.puts('User does not exist');
	});
	sys.puts('Authenticating user');


This example will print out two messages "Authenticating user" and the result/success of the authentication. The order relies on the speed of the database and likely "Authenticating user" will be printed out first. You can compare this to a setTimout example

此示例将打印出两个消息“正在验证用户”和身份验证的结果/成功。 该顺序取决于数据库的速度,可能会首先打印出“身份验证用户”。 您可以将其与setTimout示例进行比较


setTimeout(function(){
	log('Bye');
}, 1);
log('Hello');


Note: The callback style with the error as first argument is aligned to the way Node.js currently works with asynchronous operations. Before that a "Promises" system was used but it has been removed. A high level implementation can abstract away from the current solution. Feel free to implement your own callback/event system with MooTools and share it with the community :)

注意:以第一个参数为错误的回调样式与Node.js当前用于异步操作的方式保持一致。 在此之前,使用了“承诺”系统,但已将其删除。 高级实现可以从当前解决方案中抽象出来。 随时使用MooTools实施自己的回调/事件系统,并与社区共享:)

Note: CommonJS actually specifies module identifiers to be lowercase. However, I like my filenames to start uppercased. You'll always see me doing "require('User')" instead of 'user' in my applications.

注意:CommonJS实际上将模块标识符指定为小写。 但是,我希望文件名以大写开头。 您将始终看到我在应用程序中执行“ require('User')”而不是“ user”。

为什么选择ServerSide MooTools? (Why ServerSide MooTools?)

One reason for the existence of JavaScript libraries is the lack of certain functionality especially on the DOM level and the enormous amount of issues between different rendering engines. You do not have any of these problems on the serverside. MooTools, as a library, works on a much lower level than some other libraries and it therefore provides useful utility functionality that we think is missing in JavaScript. In addition to that, even if there are CommonJS specifications, some implementations differ from the others. MooTools Core and an abstraction layer on top of that (like Deck ( http://github.com/keeto/deck )) can greatly benefit you and help you eliminate or reduce low level problems you may encounter at some point during development.

存在JavaScript库的原因之一是缺少某些功能,尤其是在DOM级别,以及不同渲染引擎之间存在大量问题。 您在服务器端没有任何这些问题。 MooTools作为一个库,其工作水平比其他一些库低得多,因此它提供了有用的实用程序功能,我们认为这是JavaScript中所缺少的。 除此之外,即使有CommonJS规范,某些实现也与其他实现不同。 MooTools Core及其之上的抽象层(例如Deck( http://github.com/keeto/deck ))可以使您受益匪浅,并帮助您消除或减少在开发过程中可能遇到的低级问题。

In addition to that the sophisticated and clean class system provided by MooTools makes it possible to write abstract plugins that will work on both the server- and the clientside without any further modifications (ie. a Language/Internalization class, a schema validator, etc.). For more information on this feel free to watch my presentation at FOSDEM 2010 (at 25:00 + Q&A).

除了MooTools提供的复杂而干净的类系统之外,还可以编写可以在服务器端和客户端上都可以使用的抽象插件,而无需进行任何进一步的修改(例如,语言/内部化类,模式验证器等)。 )。 有关此方面的更多信息,请随时观看我在FOSDEM 2010上的演讲(25:00 +问答)

其他(非与MooTools相关的)东西 (Other (non-MooTools Related) Stuff)

奖励:使用Node.js在TextMate中执行Node.js中的脚本 (Bonus: Execute a Script in Node.js from TextMate by Using Node.js)

Add this command as a script:

将此命令添加为脚本:


#!/usr/bin/env node

var sys = require('sys'),
    spawn = require('child_process').spawn;

spawn('node', [process.ENV.TM_FILEPATH]).stdout.addListener('data', function(data) {
  sys.puts(data);
});


Like this:

像这样:

Node.js and MooTools in TextMate

Click the image above for a larger view.

单击上面的图像查看大图。

关于克里斯托弗·波耶(Christoph Pojer) (About Christoph Pojer)

Christoph is a student of Software Engineering and Business Administration at the Graz University of Technology in Austria. He is an experienced web developer and a Core Developer of the MooTools JavaScript Framework.

Christoph是奥地利格拉茨科技大学的软件工程和工商管理专业的学生。 他是一位经验丰富的Web开发人员,也是MooTools JavaScript框架的核心开发人员。

Christoph's WebsiteGitHubTwitterForge

Christoph的网站GitHubTwitterForge

翻译自: https://davidwalsh.name/mootools-nodejs

mootools

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值