什么是模块化,为什么要模块化?回答这个问题需要了解前端的发展历史,我们从 前端发展早期,前端进入服务器时代,前端发展繁荣时期 来了解 JavaScript 模块化。
前端发展早期
那个时候业务非常简单,可能就处理一些点击、弹框、表单提交等逻辑,在页面中通过 script 标签引入一个 JS 文件就搞定了
<!-- index.html -->
...
<script src="main.js"></script>
...
即使业务复杂一点的,多引入几个 JS 文件也可以搞定
<!-- index.html -->
...
<script src="main.js"></script>
<script src="a.js"></script>
<script src="b.js"></script>
...
但需要注意引入顺序,以及命名空间污染等问题。
前端进入服务器时代
由Ryan Dahl开发,2009年5月发布的 Node.js 让 JS 不仅仅运行在浏览器端,也可以在服务器端运行。
这也带来一个问题,由于服务器的复杂性,代码量巨大,所以需要一个机制来管理这些代码。
这个机制需要具备三个方面能力:
- 代码可维护性: 不相干的代码是相互独立模块,每个模块的升级或者重构不会影响其他的模块
- 解决命名空间污染的问题: 不相干的代码他们的命名,即使相同也不能相互冲突
- 代码复用能力: A 文件的代码,需要用到 B 文件的方法,不是粗暴的粘贴复制,而是直接引用 B 的方法就可以了,以后重构优化就不需要每个文件去改。
Common.js 应运而生,用于处理 Node.js 的代码管理。
// a.js
var a = {}
module.export = a
// b.js
var a = require('./a')
由于 Node.js 是在服务器端运行的,操作本地磁盘,延迟低,所以 Common.js 是同步引入的。
前端发展繁荣时期
随着互联网的高速发展,前端复杂度越来越高,很多时候并不亚于后端,所以也需要 Common.js。
browserify 让浏览器端也可以用Common.js。
先安装 browserify:
npm install -g browserify
// main.js
var add = require('./a.js')
console.log(add(1,2))
// a.js
var add = function(){ return a+b }
module.exports = add
browserify main.js -o bundle.js
script 标签直接引入 bundle.js 就可以用了。
在 bundle.js 代码中我们可以看到,Common.js 创建了文件依赖关系和相互独立的命名空间:
(function() {
function r(e, n, t) {
function o(i, f) {
...
...
}
}
})()(
{
1: [
function(require, module, exports) {
var add = function(a, b) {
return a + b;
};
module.exports = add;
},
{}
],
2: [
function(require, module, exports) {
var add = require("./a.js");
console.log(add(1, 2));
},
{ "./a.js": 1 }
]
},
{},
[2]
);
由于 Common.js 同步的特性,如果 var add = require('./a.js') 需要执行很长时间,这时候浏览器就会假死,所以浏览器需要异步执行,Common.js 并不满足,AMD 应运而生。
AMD
AMD 全称是 Asynchronous Module Definition,从名字就可以看出,它最大的特色就是异步。具体用法:
define(['aModule', 'bModule'], function(aModule, bModule) {
console.log(aModule.hello());
});
当 aModule 和 bModule 加载完毕后,再会执行后面的回调,从而实现异步的能力。
实现 AMD 规范的有: require.js。
ES Module
浏览器除 AMD 外,还有 CMD(主要区别:AMD 预加载,CMD 懒加载)等规范,为统一浏览器模块化规范,以及浏览器端和服务器端的大统一,ECMA 制定了 ES Modules 规范:
// a.js
export function add() {return a+b}
// b.js
import {add} from a
add(1,2)
从此以后,开发者在开发工具或者框架时,就不用再兼容各种模块化规范了。