AMD vs. CommonJS 竞争,但同样有效的标准
本文强调使用AMD要多于CommonJS,但是实际上它们各有用武之地。
AMD更适合浏览器优先开发,适用于一步行为,以及简化向后兼容,但是它并不包含文件I/O的概念。它支持对象,函数,构造器,字符串,JSON以及很多类型的模块,可以直接在浏览器中运行,具有较高的灵活性。
CommonJS这是适于作为服务优先的解决方案,更是和同步行为,项John Hann所推荐的,不存在全局的baggage,并且对未来的服务端开发有更强的适应性。这样说是因为,CJS支持非封装的模块,感觉更像是ES.next/Harmony的规范,对AMD中强制要求的define()
在这里不再被强制要求。但是CJS模块仅支持对象作为模块。
虽然不同模块的不同规范可能令人混淆,但是你可能会对混合AMD/CJS和通用AMD/CJS模块感兴趣。
基础AMD混合规范(John Hann)
define( function (require, exports, module){
var shuffler = require('lib/shuffle');
exports.randomize = function( input ){
return shuffler.shuffle(input);
}
});
AMD/CommonJS通用模块定义(Variation 2, UMDjs)
/**
* exports object based version, if you need to make a
* circular dependency or need compatibility with
* commonjs-like environments that are not Node.
*/
(function (define) {
//The 'id' is optional, but recommended if this is
//a popular web library that is used mostly in
//non-AMD/Node environments. However, if want
//to make an anonymous module, remove the 'id'
//below, and remove the id use in the define shim.
define('id', function (require, exports) {
//If have dependencies, get them here
var a = require('a');
//Attach properties to exports.
exports.name = value;
});
}(typeof define === 'function' && define.amd ? define : function (id, factory) {
if (typeof exports !== 'undefined') {
//commonjs
factory(require, exports);
} else {
//Create a global function. Only works if
//the code does not have dependencies, or
//dependencies fit the call pattern below.
factory(function(value) {
return window[value];
}, (window[id] = {}));
}
}));
扩展的UMD插件(我和Thomas Davis)
core.js
// Module/Plugin core
// Note: the wrapper code you see around the module is what enables
// us to support multiple module formats and specifications by
// mapping the arguments defined to what a specific format expects
// to be present. Our actual module functionality is defined lower
// down, where a named module and exports are demonstrated.
;(function ( name, definition ){
var theModule = definition(),
// this is considered "safe":
hasDefine = typeof define === 'function' && define.amd,
// hasDefine = typeof define === 'function',
hasExports = typeof module !== 'undefined' && module.exports;
if ( hasDefine ){ // AMD Module
define(theModule);
} else if ( hasExports ) { // Node.js Module
module.exports = theModule;
} else { // Assign to common namespaces or simply the global object (window)
(this.jQuery || this.ender || this.$ || this)[name] = theModule;
}
})( 'core', function () {
var module = this;
module.plugins = [];
module.highlightColor = "yellow";
module.errorColor = "red";
// define the core module here and return the public API
// this is the highlight method used by the core highlightAll()
// method and all of the plugins highlighting elements different
// colors
module.highlight = function(el,strColor){
// this module uses jQuery, however plain old JavaScript
// or say, Dojo could be just as easily used.
if(this.jQuery){
jQuery(el).css('background', strColor);
}
}
return {
highlightAll:function(){
module.highlight('div', module.highlightColor);
}
};
});
myExtension.js
;(function ( name, definition ) {
var theModule = definition(),
hasDefine = typeof define === 'function',
hasExports = typeof module !== 'undefined' && module.exports;
if ( hasDefine ) { // AMD Module
define(theModule);
} else if ( hasExports ) { // Node.js Module
module.exports = theModule;
} else { // Assign to common namespaces or simply the global object (window)
// account for for flat-file/global module extensions
var obj = null;
var namespaces = name.split(".");
var scope = (this.jQuery || this.ender || this.$ || this);
for (var i = 0; i < namespaces.length; i++) {
var packageName = namespaces[i];
if (obj && i == namespaces.length - 1) {
obj[packageName] = theModule;
} else if (typeof scope[packageName] === "undefined") {
scope[packageName] = {};
}
obj = scope[packageName];
}
}
})('core.plugin', function () {
// define your module here and return the public API
// this code could be easily adapted with the core to
// allow for methods that overwrite/extend core functionality
// to expand the highlight method to do more if you wished.
return {
setGreen: function ( el ) {
highlight(el, 'green');
},
setRed: function ( el ) {
highlight(el, errorColor);
}
};
});
app.js
$(function(){
// the plugin 'core' is exposed under a core namespace in
// this example which we first cache
var core = $.core;
// use then use some of the built-in core functionality to
// highlight all divs in the page yellow
core.highlightAll();
// access the plugins (extensions) loaded into the 'plugin'
// namespace of our core module:
// Set the first div in the page to have a green background.
core.plugin.setGreen("div:first");
// Here we're making use of the core's 'highlight' method
// under the hood from a plugin loaded in after it
// Set the last div to the 'errorColor' property defined in
// our core module/plugin. If you review the code further down
// you'll see how easy it is to consume properties and methods
// between the core and other plugins
core.plugin.setRed('div:last');
});