CommonJs, AMD/RequireJs,CMD/seajs, UMD, webpack

本文深入讲解JavaScript中的多种模块化标准,包括CommonJS、AMD、CMD和UMD等规范的特点及应用,对比RequireJS与SeaJS的异同,并探讨Webpack作为打包工具的角色。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

JavaSript模块化

在了解AMD,CMD规范前,还是需要先来简单地了解下什么是模块化,模块化开发?
模块化是指在解决某一个复杂问题或者一系列的杂糅问题时,依照一种分类的思维把问题进行系统性的
分解以之处理。模块化是一种处理复杂系统分解为代码结构更合理,可维护性更高的可管理的模块的方
式。可以想象一个巨大的系统代码,被整合优化分割成逻辑性很强的模块时,对于软件是一种何等意义的
存在。对于软件行业来说:解耦软件系统的复杂性,使得不管多么大的系统,也可以将管理,开发,维护
变得“有理可循”。
还有一些对于模块化一些专业的定义为:模块化是软件系统的属性,这个系统被分解为一组高内聚,低
耦合的模块。那么在理想状态下我们只需要完成自己部分的核心业务逻辑代码,其他方面的依赖可以通过
直接加载被人已经写好模块进行使用即可。
首先,既然是模块化设计,那么作为一个模块化系统所必须的能力:

1. 定义封装的模块。
2. 定义新模块对其他模块的依赖。
3. 可对其他模块的引入支持。

好了,思想有了,那么总要有点什么来建立一个模块化的规范制度吧,不然各式各样的模块加载方式只
会将局搅得更为混乱。那么在JavaScript中出现了一些非传统模块开发方式的规范 CommonJS的模块规
范,AMD(Asynchronous Module Definition),CMD(Common Module Definition)等。
http://blog.chinaunix.net/uid-26672038-id-4112229.html

@Seasons123 Seasons123 changed the title from mst-CMD,AMD,UMD,commonjs,requirejs,seajs to mst-关于模块化:CMD,AMD,UMD,commonjs,requirejs,seajs on 22 Jun

@Seasons123 Seasons123 changed the title from mst-关于模块化:CMD,AMD,UMD,commonjs,requirejs,seajs tomst-关于模块化:CMD,AMD,UMD,commonjs,requirejs,seajs,webpack on 22 Jun


 
Owner

Seasons123 commented on 22 Jun  

commonjs

commonjs起初是服务端模块的规范,nodejs就是采用这个规范。CommonJs原来是叫ServerJs,从名字可以看出是专攻服务端的,为了统一前后端而改名CommonJs。它的规范是一个单独的文件就是一个模块。加载模块使用require方法,该方法读取文件并执行,最后导出一个exports对象。commonjs是同步加载模块,加载完成后执行操作。服务端require一个模块,直接就从硬盘或者内存中读取了,消耗的时间可以忽略,就没有必要采用异步方式的来加载。但是如果我们考虑到浏览器端的话,就肯定知道,同步加载,阻塞页面的渲染,造成页面白屏,或者卡死等现象,对于用户体验肯定是不友好的。另外,资源的加载方式与服务端完全不同,在浏览器端,需要从服务端来下载这个文件,然后运行里面的代码才能得到API,需要花费一个http请求,也就是说,require后面的一行代码,需要资源请求完成才能执行。由于浏览器端是以插入<script>标签的形式来加载资源的(ajax方式不行,有跨域问题),没办法让代码同步执行,所以像commonjs那样的写法会直接报错。所以就有了AMD,CMD.

AMD

即Asynchronous Module Definition的缩写,字面意思”异步模块定义”,就是一种规范。依赖前置(依赖在使用之前都必须提前加载)。requirejs可以简单理解为AMD规范的一种实现。下面介绍。
AMD写模块的api如下:
define(id,dependencies,factory);
(1)id
string类型,一般表示模块名称,或者说标识,是一个可选参数。如果该参数不存在的话。如果没有提供
该参数,模块的名字应该默认为模块加载器请求的指定脚本的名字。如果提供了该参数,模块名必是“顶级”的和绝对的(不允许相对名字)。
模块名的格式

模块名用唯一标识定义,它们同样在依赖数组中使用。AMD的模块命名规范是Commonjs模块命名规范的
超集。
模块名是由一个或多个单词以正斜杠为分隔符拼接成的字符串
单词须为驼峰形式,或者”.”,”..”
模块名不允许使用文件扩展名的形式,如”.js”
模块名可以为”相对的”或者”顶级的”。如果首字符为”.”或者”..”则为”相对的”模块名
顶级的模块名从根命名空间的概念模块解析
相对的模块名从”require”书写和调用的模块解析

(2) dependencies
数组类型。是定义中模块所依赖模块的一个数组。依赖模块必须根据模块的工厂方法优先级执行,并且执
行的结果应该按照数组中的位置顺序以参数的形式传入(定义中模块的)工厂方法中。依赖的模块名如果是
相对的,应该解析为相对定义中的模块。相对名解析为相对于模块的名字,并非相对于寻找该模块的名字
和路径。该参数也是可选参数,如果没有这个参数,它默认为[“require”, “exports”, “module”]。然而,如
果工厂方法的形参个数小于3,加载器会选择以函数指定的参数个数调用工厂方法
(3)factory
值的类型多选。是模块初始化要执行的函数或者对象。如果是函数的话,它应该只被执行一次。如果是对
象,此对象应该为模块的输出值。如果工厂方法返回一个值(对象,函数,或任意强制类型转换为true的
值),应该被设置为模块的输出值。以上引用https://github.com/amdjs/amdjs-api/wiki/AMD-
(%E4%B8%AD%E6%96%87%E7%89%88),原文链接markdown语法限制会跳错,没办法了,只能换成短连
接了。

UMD

即Universal Module Definition,应该算是AMD和commonjs的一个糅合。
其原理:先判断是否支持nodejs的模块(exports)是否存在,如果存在就是用nodejs模块模式,然后再判断
是否支持AMD(define是否存在),如果存在就使用AMD方式加载模块.

CMD

CMD 即Common Module Definition通用模块定义,CMD规范是国内发展出来的,就像AMD有个
requireJS,CMD有个浏览器的实现SeaJS(作者是国内大牛淘宝前端布道者玉伯),SeaJS要解决的问题和
requireJS一样,只不过在模块定义方式和
模块加载(可以说运行、解析)时机上有所不同

语法:Sea.js 推崇一个模块一个文件,遵循统一的写法
define:define(id?, deps?, factory)

因为CMD推崇:一个文件一个模块,所以经常就用文件名作为模块id
CMD推崇依赖就近,所以一般不在define的参数中写依赖,在factory中写
factory有三个参数:function(require, exports, module)

require是 factory 函数的第一个参数
require(id) 是一个方法,接受 模块标识 作为唯一参数,用来获取其他模块提供的接口
exports 是一个对象,用来向外提供模块接口
module 是一个对象,上面存储了与当前模块相关联的一些属性和方法

demo

// 定义模块  myModule.js
define(function(require, exports, module) {
  var $ = require('jquery.js')
  $('div').addClass('active');
});

// 加载模块
seajs.use(['myModule.js'], function(my){

});

AMD,CMD 区别 :1st_place_medal:

关于这两个的区别网上可以搜出一堆文章,简单总结一下
最明显的区别就是在模块定义时对依赖的处理不同

AMD推崇依赖前置,在定义模块的时候就要声明其依赖的模块
CMD推崇就近依赖,只有在用到某个模块的时候再去require

这种区别各有优劣,只是语法上的差距,而且requireJS和SeaJS都支持对方的写法

AMD和CMD最大的区别是对依赖模块的执行时机处理不同,注意不是加载的时机或者方式不同
很多人说requireJS是异步加载模块,SeaJS是同步加载模块,这么理解实际上是不准确的,其实加载模
块都是异步的,只不过AMD依赖前置,js可以方便知道依赖模块是谁,立即加载,而CMD就近依赖,需要
使用把模块变为字符串解析一遍才知道依赖了哪些模块
,这也是很多人诟病CMD的一点,牺牲性能来带
来开发的便利性,实际上解析模块用的时间短到可以忽略。
为什么我们说两个的区别是依赖模块执行时机不同,为什么很多人认为ADM是异步的,CMD是同步的
(除了名字的原因。。。)
同样都是异步加载模块
(1)AMD在加载模块完成后就会执行该模块,所有模块都加载执行完后会进入
require的回调函数,执行主逻辑,这样的效果就是依赖模块的执行顺序和书写顺序不一定一致,看网络速
度,哪个先下载下来,哪个先执行,但是主逻辑一定在所有依赖加载完成后才执行。
(2)CMD加载完某个依赖模块后并不执行,只是下载而已,在所有依赖模块加载完成后进入主逻辑,遇
到require语句的时候才执行对应的模块,这样模块的执行顺序和书写顺序是完全一致的。
这也是很多人说AMD用户体验好,因为没有延迟,依赖模块提前执行了,CMD性能好,因为只有用户需
要的时候才执行的原因。http://www.cnblogs.com/dolphinX/p/4381855.html

requirejs seajs

这两个分别是ADM,CMD的实现方案,肯定有异同。
(requirejs的应用示例:静态文件服务器devServer.js)。
相同之处:
两者都是模块加载器,倡导js模块化开发的理念。
不同之处:
(1)定位有差异。RequireJS 想成为浏览器端的模块加载器,同时也想成为 Rhino / Node 等环境的模块加载
器。Sea.js 则专注于 Web 浏览器端,同时通过 Node 扩展的方式可以很方便跑在 Node 环境中。
(2)遵循的规范不同。RequireJS 遵循 AMD(异步模块定义)规范,Sea.js 遵循 CMD (通用模块定义)规
范。规范的不同,导致了两者 API 不同。Sea.js 更贴近 CommonJS Modules/1.1 和 Node Modules 规范。
(3)推广理念有差异。RequireJS 在尝试让第三方类库修改自身来支持 RequireJS,目前只有少数社区采
纳。Sea.js 不强推,采用自主封装的方式来“海纳百川”,目前已有较成熟的封装策略。
(4)对开发调试的支持有差异。Sea.js 非常关注代码的开发调试,有 nocache、debug 等用于调试的插件。
RequireJS 无这方面的明显支持。
(5)插件机制不同。RequireJS 采取的是在源码中预留接口的形式,插件类型比较单一。Sea.js 采取的是通
用事件机制,插件类型更丰富。
引用seajs/seajs#277

什么是Webpack?

事实上它是一个打包工具,而不是像RequireJS或SeaJS这样的模块加载器,通过使用Webpack,能够像
Node.js一样处理依赖关系,然后解析出模块之间的依赖,将代码打包。(如该项目中使用的模块化和打
包工具webpack的配置文件webpack.config.js)。
webpak不仅支持打包,而且支持AMD 和 CommonJS 方式来做模块化开发,所以打算尝试一下webpack
来实现模块化。

 
@Seasons123
 
Owner

Seasons123 commented on 22 Jun

扩展阅读:

AMD规范文档 https://github.com/amdjs/amdjs-api/wiki/AMD
amdjs 的 require 接口文档 https://github.com/amdjs/amdjs-api/wiki/require
amdjs 的接口文档 https://github.com/amdjs/amdjs-api/wiki
RequireJS官网接口文档 http://www.requirejs.org/docs/api.html

模块系统 seajs/seajs#240
前端模块化开发的价值 seajs/seajs#547
前端模块化开发那点历史 seajs/seajs#588
CMD 模块定义规范 seajs/seajs#242
SeaJS API快速参考 seajs/seajs#266
从 CommonJS 到 Sea.js seajs/seajs#269

RequireJS和AMD规范 http://javascript.ruanyifeng.com/tool/requirejs.html
CommonJS规范 http://javascript.ruanyifeng.com/nodejs/commonjs.html
Javascript模块化编程 http://www.ruanyifeng.com/blog/2012/10/javascript_module.html
Javascript模块化编程 http://www.ruanyifeng.com/blog/2012/10/asynchronous_module_definition.html

知乎 AMD 和 CMD 的区别有哪些? http://www.zhihu.com/question/20351507

JavaScript模块化开发 - CommonJS规范 http://www.feeldesignstudio.com/2013/09/javascript-module-pattern-commonjs
JavaScript模块化开发 - AMD规范 http://www.feeldesignstudio.com/2013/09/javascript-module-pattern-amd

模块化设计 http://baike.baidu.com/view/189730.htm
模块化 http://baike.baidu.com/view/182267.htm


 
Owner

Seasons123 commented on 22 Jun

阮老师的相关文集:
Javascript模块化编程(一):模块的写法
http://www.ruanyifeng.com/blog/2012/10/javascript_module.html

Javascript模块化编程(二):AMD规范
http://www.ruanyifeng.com/blog/2012/10/asynchronous_module_definition.html

Javascript模块化编程(三):require.js的用法
http://www.ruanyifeng.com/blog/2012/11/require_js.html


 
Owner

Seasons123 commented on 22 Jun  

关于各个模块规范的老底吕师兄写过一篇也很好:
:+1: :100: js模块化历程http://www.cnblogs.com/lvdabao/p/js-modules-develop.html :1st_place_medal:

@Seasons123 Seasons123 changed the title from mst-关于模块化:CMD,AMD,UMD,commonjs,requirejs,seajs,webpack to mst-关于模块化:Commonjs, AMD, UMD, CMD, Requirejs, seajs, webpack on 22 Jun

@Seasons123 Seasons123 changed the title from mst-关于模块化:Commonjs, AMD, UMD, CMD, Requirejs, seajs, webpack to Commonjs, AMD, UMD, CMD, Requirejs, seajs, webpack on 22 Jun

@Seasons123 Seasons123 changed the title from Commonjs, AMD, UMD, CMD, Requirejs, seajs, webpack to mst-关于模块化:CommonJs, AMD/RequireJs,CMD/seajs, UMD, webpack on 22 Jun

@Seasons123 Seasons123 changed the title from mst-关于模块化:CommonJs, AMD/RequireJs,CMD/seajs, UMD, webpack to CommonJs, AMD/RequireJs,CMD/seajs, UMD, webpack on 22 Jun

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值