在 Node.js 上使用 Dojo
Node.js 最近非常火热,不仅开源社区对其非常关注,甚至微软对其也提供了官方的支持,从而让 Node.js 也能运行于 Windows 系统,这为 Node.js 的进一步流行奠定了基础。本文将介绍 Node.js 和 Dojo 的模块管理机制,并在此基础上详细介绍在 Node.js 上运行 Dojo 框架的方案。最后通过一个例子,演示如何用 Dojo 的 DTL 模块来解析一个基于 Django 模板语言的模板文件。
一个普遍的看法是 Node.js 让 JavaScript 成为了服务器端语言,于是自然很多人都把 Node.js 看成了一个 Web Server。但实际上并非如此,Node.js 只是一个 JavaScript 宿主环境,它解释并运行 JavaScript,同时提供了很多原生对象(Native Object)让 JavaScript 可以做更多的事情,例如进行网络通信、文件处理等等。就像,您可以用 Perl、Python 写一个 Web Server 一样,您也可以用 JavaScript 写 Web Server。Node.js 适合创建 Web Server,因为它能高效的处理并发请求,但它自身并不是一个 Web Server。澄清这一点,我们就完全可以像用 Perl 一样来用 JavaScript,让它成为一种工具语言。当出现产品级的基于 Node.js 的 Web Server 时,我们也就能更加容易的上手进行 Web 服务器端开发。
为什么要在 Node 上运行 Dojo
JavaScript 本身是一个设计非常精简的语言,功能相对简单,因为它的初衷并不是用来开发复杂的应用,而只是用于自动化的来操纵浏览器。面对日益复杂的前端应用,已经出现了很多类库来解决这个问题,比如 jQuery、ExtJs、Dojo、YUI。这些类库除了实现了浏览器兼容的 API,同时还有一大部分功能是纯粹的用来增强 JavaScript 的功能。而这部分功能,正是服务器端和浏览器端通用的,我相信如果在这方面提供一致性,一定是广大 Web 开发人员所喜闻乐见的,这也是我写这篇文章的目的。
这么多类库之中,Dojo 是所有当前类库中最适合运行于 Node.js 的,原因有四:
- Dojo 和 Node.js 都基于 CommonJS 的 Module 规范。
- Dojo 天然支持 Node.js,很好的对浏览器相关代码做了隔离。启动脚本能自动检测 Node.js 运行环境检测,无需任何修改即可直接使用。
- Dojo 所采用的单元测试框架和打包工具都是用 JavaScript 写成,可以直接在 Node.js 上运行。从而,Dojo+Node.js 可以完成整个应用开发的生命周期。
- Dojo 有完整的面向对象体系,适合大型应用的开发。
Node.js 和 Dojo 的模块加载机制
Node.js 和 Dojo 都遵循 CommonJS 的模块相关规范。Node.js 支持的是 Module1.0 规范,而 Dojo 支持的是 AMD(Asynchronous Module Definition,即异步模块定义)规范。虽然是两个规范,但它们都是描述了模块的定义和加载机制,有很多共同点。这就为 Dojo 运行于 Node 提供了天然的基础。在规范中,JavaScript 文件和模块是一一对应的关系,每个文件就是一个模块,模块之间可以通过相对路径来引用。
对于 Node.js,要使用一个模块非常简单,直接用 Module1.0 规范中定义的 require 函数即可,例如:
但对于 Dojo 支持的 AMD 规范,则定义的是一个异步载入机制,稍微复杂。因为这个规范强调的是异步,就需要通过一个回调函数来使用模块,这个回调函数会在依赖的模块载入完成之后被调用,例如:
Dojo 中所有的模块都是通过 define 函数定义的,很显然,不支持 AMD 规范的 Node.js 是不认识 define 函数,不能直接执行这些模块的。因此,Dojo 必须自己维护模块的加载和执行,这也完全符合 Dojo 在浏览器端的行为,只是读取模块代码的逻辑从 HTTP 请求转换到了读取文件,其它逻辑维持不变。在 Dojo 的初始化代码中已经包含了对 Node.js 环境的检测,会自动根据环境使用不同的方法载入模块。
在 CommonJS 规范的基础上,Node.js 和 Dojo 还都另外引入了类似的包(package)的概念。所谓一个包就是一个文件夹,在 Node.js 下可以直接 require('packageIdentifer' ),而 Dojo 则是通过 define(['packageIdentifier' ], callback) 来使用一个包。这时 Node.js 会寻找文件夹下的 index.js 或者 index.node 模块,而 Dojo 则寻找的是 main.js 模块。同样,因为应用是运行于 Dojo 框架之下,包的概念以 Dojo 的实现为准。
如果把模块的加载理解为 Java 中的 ClassLoader,那么 Dojo 就是实现了自己的 ClassLoader,来取代 Node.js 自身的行为。因此,要在 Node.js 上运行一个基于 Dojo 的应用,用的是类似下面的命令:
理解了这些内容,我们就可以进一步了解如何配置 Dojo,让其在 Node.js 上运行基于 Dojo 的应用程序。
在 Node 上运行 Dojo
下面通过一个简单的例子来看,如何在 Node 上运行基于 Dojo 的程序。
1. 引入并配置 Dojo
我们知道,在浏览器端引入 Dojo 之类的框架,首先需要在页面中引入框架自身,通常是通过 <script> 标签引入,在引入的同时,还可以传递参数,对于 Dojo 来说,可以通过两种途径,一种是在 <script> 标签中加入属性,例如:
在 Node.js 中,方法是类似的,需要一个 Node.js 可运行的模块来引入 Dojo。例如,创建一个 bootstrap.js 文件,包含如下内容:
Node.js 中定义全局变量的方法和浏览器端略有区别,它是通过为 global 增加一个属性来定义全局变量。随后,通过 require 函数引入 Dojo,相当于 HTML 页面中的 <script> 标签。因此,在本质上,这个 bootstrap.js 文件就是包含配置信息的 Dojo。直接使用下面的代码就可以在 Node 上运行 Dojo 了:
当然,这行命令什么也没有干,只是运行了一下 Dojo。底下我们来看如何在 Dojo 里运行自己的 Dojo 程序。
2. 定义应用程序入口
上面提到了通过 dojoConfig 这个全局变量来配置 Dojo,除此之外,其中还可以定义自己的 package,每个 package 都可能是一个应用,或者一个类库。所有的 package 都放在 packages 数组中:
Dojo 通过 load 参数来获得应该执行的 package,在这个 package 下的 main.js 模块会被执行,下面将会介绍。
3. 执行应用程序
如前面所述,package 本身并没有特别的地方,它就是一个文件夹。当仅指定一个 package,而非具体的模块时,Dojo 就会自动执行其下的 main.js 文件。这个 main.js 模块和普通的模块本质上也没有任何区别,但一般这个模块中仅包含应用初始化的逻辑,从而能够启动应用的执行。
现在我们先来看一个简单的“Hello world”的例子。我们不使用任何 Dojo 的模块,而是只用 define 来定义一个自己的模块,让它打印“Hello world”。我们在 main.js 里放如下的内容:
这样,我们将会在命令行窗口看到输出的“Hello world”。这里我们并没有用任何的 Dojo 模块,而是仅仅让 Dojo 去寻找到 main.js 并执行它。那下面来看如何去依赖 Dojo 的模块来实现自己的应用逻辑。
这个例子将使用 Dojo 对 Django 模板语言(DTL)模块的实现来做字符串的转换:
后记
有人曾预言 Node.js 将取代 PHP 成为最流行的服务器端语言,无论您信不信,Node.js 正在快速的演变和发展,并获得越来越多的关注。基于 Node.js 的一些 Web Server 已经可以用于商业用途,例如 http://expressjs.com。这让 JavaScript 这个简洁而优雅的语言发挥散发出越来越大的魅力。而 Dojo 作为一个功能强大的 JavaScript 框架,在企业级应用中一直备受青睐,借助其对 Node.js 的完美支持,相信也能发挥出更大的作用。
本文首发于IBM Developerworks,原文地址:http://www.ibm.com/developerworks/cn/web/1203_wangpei_dojonodejs/