如果没有接触过大型复杂的WEB项目,你是不会对模块化感兴趣的,所以假设你有折腾过大型项目的经验,在项目过程中你会有如下困惑:
- 将实现的功能细节隐藏起来,仅暴露接口
- 将大型项目分成若干部分
- 可复用的功能代码库
那么如何解决这些问题呢?
JavaScript 语言本身缺乏原生的模块化机制,那么只好另辟蹊径:
使用闭包(Closure)特性去模拟模块化
var MyModule = (function() { |
以上代码确实解决了模块化的问题,但是当模块暴增之后,如何解决之间的依赖呢?是个麻烦问题!
最开始学习WEB开发的时候有以下两种办法:
- 在
header
里逐个加入script
标签,引入需要的模块就OK了。 - 另一种方法,将所有的模块有序放在一个JS文件里,整个应用依赖这一个JS文件就OK了,比如 Google closure compiler 这个工具可以方便合成,从而减少HTTP请求。
以上两种方法在jQuery时代很流行,很暴力很方便,但最大的坑点在于后期维护成本问题,以及资源浪费。
越大的WEB项目越是头疼,有时候干脆选择重新开发,而不愿意在原有基础上增删改查。
比如你只需要 jQuery 库中的某几个功能,然而你将整个 library 通过 < script > 方式引入,必然导致浪费带宽,如此一来像京东一类的大流量电商,企业成本瞬间增加许多。
后来大家越来越重视这些问题,为了解决以上问题,诸如CommonJS
这类机制就登上了舞台。
CommonJS in the Server side
CommonJS 是一个有志于构建 JavaScript 生态圈的组织,在ES6还没成熟的时候,这很流行。
CommonJS 解决问题的方案,是提供模块的 export 和 require 机制,将模块隔离在各自独立的上下文中运行,类似闭包。
例如,以下代码片段是为了导出变量”foo”而创建:
// library.js 文件 |
您可以使用“require”功能,将以上库导入以下模块:
var lib = require("./library.js"); |
以上就解决了依赖问题,最大程度地释放了开发者双手,提高了效率,CommonJS崇尚“小而精”(lean and mean)的审美哲学,模块专注做好自己的东西,尽量不添加多余的功能,但这仅仅是服务端的解决方案。
如今 CommonJS 是 JavaScript 中采用较广泛的模块系统,Node 模块的 NPM
也是支持该规范,起了积极的推动作用,我们使用 CommonJS 思想,可以轻松下载、安装和配置若干库,将后端的软件管理包(如maven、apt-get、yum、brew、gem、pip、bower)思想引入前端,实现模块的中心化管理,从此打开了大前端的门。
CommonJS in the Browser side
在 CommonJS/Modules 1.0 时代,require 是同步的,对于服务器而言,然而在浏览器端问题多多,当需要异步执行,这是有缺陷的,所以出现了各种解决方案,如服务器端组件、AMD(RequireJS)、CMD(SeaJS)、Modules/Wrappings、CommonJS/Modules 2.0 等。
后来其中两个规范被广泛应用,他们就是:AMD和CMD.
AMD
AMD是”Asynchronous Module Definition”的缩写,意思就是”异步模块定义”。它采用异步方式加载模块,模块的加载不影响它后面语句的运行,它是 RequireJS 在推广过程中对模块定义的规范化的产出,也是 CommonJS 的一个分支。
采用异步方式加载模块,模块的加载不影响它后面语句的 define 定义模块
define(["./a","./b"],function(a,b){ |
require加载模块,但是不同于CommonJS,它要求两个参数:
require([module],callback) |
CMD
CMD是”Common Module Definition”的缩写,一种模块化规范,国内的玉伯大神提出的规范方案,SeaJS就遵循该规范。
前端模块化工具
目前NPM上有20+万个NodeJS模块,它们都是通过CommonJS的方式打包的,除了特定的可以使用CommonJS模块加载器加载的模块,大部分NodeJS模块无法直接使用到浏览器环境中,要将 CommonJS 应用到浏览器端应用(Browser side application),就需要额外的工具来实现 Build process,例如 Browserify、Webpack等工具,Browserify 是一个供浏览器环境使用的模块打包工具,运行 Browserify 后,它将从某个固定的入口搜索所有的依赖代码,随后打包成单个JS文件,减少 HTTP 请求数,并压缩文件,减少代码的整体大小,从而加速页面的加载。
类似 Browserify 的工具的思路就是:分析代码中的模块依赖关系(require, import, whatever),然后按需将这些模块打包成一个文件,如bundle.js,让浏览器端应用加以依赖
Browserify 命令对你的代码进行打包了:
browserify index.js > bundle.js |
然后只需在 HTML 页面中添加一个 < script > 标签即可
<script src="bundle.js"></script> |
鉴于目前的状态,还是建议大家更倾向于学习Webpack,可以参考外文: plug-and-play template for getting started 、针对更复杂用例的 how-to guide for webpack,或者中文参考教程:Webpack 中文指南
参考
1.CommonJS规范 (By 阮一峰)
2.Require.js 规范文档
3.从 CommonJS 到 Sea.js
4.Browserify 使用指南