为什么说CommonJS只适用于非浏览器应用程序?

42

为什么不将其作为Javascript的通用组件模式,包括在浏览器执行的Javascript中使用?

乍一看,这似乎是一种很好的方式来对我目前正在处理的项目进行模块化,该项目由大量的Javascript代码库组成,其中有许多组件,其中一些组件相互交互。


CommonJS(通用模块规范)类似于Adobe AIR,我认为它是一个在传统浏览器中无法运行的API。 但它仍然是JavaScript,只是使用了不同的API。 例如,在浏览器中你有DHTML或DOM,而在CommonJS中,你有另一个在浏览器外不相关的API。 - user475434
1个回答

73

对于浏览器而言,CommonJS确实是适合的,但需要注意一些细节。CommonJS模块模式非常好用(在我个人看来),并且也是 ECMAScript Harmony(JavaScript语言的下一个版本)提出的模块系统的一个好的过渡方案。具体来说,Harmony模块将无法访问全局对象(“window”对象)。

有些人认为CommonJS模块不适合于浏览器,原因在于它们不能通过<script>标签直接加载,需要一些服务器端的帮助。例如,假设你有一个能够输出“convertToHTML”函数的markdown库,你可以创建以下这样一个模块:

var convertToHTML = require("markdown").convertToHTML;
exports.mangleSomeText = function() {
    // do something then call convertToHTML
}

这种方法不能通过脚本标签工作的原因有几个(作用域没有包装,所以 convertToHTML 会被附加到 window 上,require 通常不会被定义,exports 需要为每个模块单独创建)。

一个带有一点服务器端帮助的客户端库可以轻松地通过脚本标签加载。或者,客户端库可以通过 XMLHttpRequest 加载脚本并执行 eval(),虽然调试体验通常不太好。

目前一个相当合理的解决方案,但也是 CommonJS 成员之间争议的焦点,是RequireJS。使用 RequireJS,您可以像这样编写您的模块:

define(function(require, exports, module) {

var convertToHTML = require("markdown").convertToHTML;
exports.mangleSomeText = function() {
    // do something then call convertToHTML
}

});

我们所做的就是在模块周围添加了define()部分。(你很容易也可以让服务器这样做,这样你甚至不需要手动编写定义部分)。

我个人已经在几个项目中使用了RequireJS,并发现它是一种简单的方法,可以在没有服务器端的情况下使用CommonJS模块。还有许多其他解决方案,如果您不依赖于运行静态JS文件,则标准的CommonJS模块是一个很好的选择。

(ObDisclaimer:我开始了CommonJS项目,所以我显然是有偏见的。)


3
严格来说,ECMAScript Harmony模块确实可以访问全局对象,只是不能访问共享的顶层词法作用域。 - Sebastian Markbåge
3
能否编写一个同时兼容requirejs和commonjs的模块? - Anderson Green
@AndersonGreen 是的,只需在底部检测 defineexports 变量,并有条件地同时处理两组代码。 - Sean Clark Hess
@SeanClarkHess 我认为这里有个打字错误。你能解释一下你所说的“并且同时有两组代码有条件地”是什么意思吗? - Anderson Green
@AndersonGreen 我写了一篇博客文章,其中包含一个示例:http://www.hacki.ly/post/45198957902/writing-javascript-for-both-node-and-browser - Wheeyls
只是为了澄清,RequireJS 实现了 AMD(异步模块加载),它有两种语法,其中一种非常类似于 CommonJS,并尝试解决相同的问题,但主要关注浏览器(即异步),而 CommonJS 更适用于服务器端(同步,文件 IO 等)。要进行简单区分,请参见:http://unscriptable.com/code/AMD-vs-CommonJS/。 - Alejandro García Iglesias

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接