从最开始的前后端混写,前后端分离,到现在的大型单页面应用。前端工程化经历了哪些?
一、JS模块化的历程
在ES5及之前,JS并没有模块这一概念。在实际多人开发过程中,为了抽离公共代码,隔离作用域、避免各个开发人员之间的变量冲突,模块化就显得十分必要。
以下JS模块的各个阶段:
IIFE 使用自执行函数来编写模块化,特点:在一个单独的函数作用域中执行代码,避免变量冲突。
1
2
3
4
5(function(){
return {
data:[]
}
})()AMD 使用requireJS来编写模块化,特点:依赖必须提前声明好。
1
2
3define('./index.js', function (code) {
// code 就是index.js 返回的内容
})CMD 使用seaJS来编写模块化,特点:支持动态引入依赖文件。
1
2
3define(function(require, exports, module) {
var indexCode = require('./index.js')
})CommonJS nodejs 中自带的模块化。
1
var fs = require('fs')
UMD 兼容 AMD,CommonJS 模块化语法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD
define(['jquery'], factory);
} else if (typeof exports === 'object') {
// Node, CommonJS之类的
module.exports = factory(require('jquery'));
} else {
// 浏览器全局变量(root 即 window)
root.returnExports = factory(root.jQuery);
}
}(this, function ($) {
// 方法
function myFunc(){};
// 暴露公共方法
return myFunc;
}));webpack(require.ensure) webpack 2.x 版本中的代码分割。
- ES Modules ES6 引入的模块化,支持import 来引入另一个 js 。
1
import a from 'a';
二、CommonJs
JavaScript最初被认为只能构建基于浏览器的应用程序,适用面狭窄。而 CommonJs API 却定义了很多普通应用程序(非浏览器)使用的 API,填补这些空白,旨在提供一个类似Python,Ruby和Java标准库。让开发者利用 CommonJS 编写的程序可以在不同的JS解析器和宿主环境中运行。
2009年,美国程序员Ryan Dahl创造了node.js项目,将javascript语言用于服务器端编程。Node
采用CommonJS模块规范,构建了node的模块系统。而在浏览器端 browserfy
和 webpack
也实现了CommonJS的模块规范。不同点在于服务端的模块加载是运行时同步加载,而浏览器端时通过提前编译打包处理。
CommonJS
相关特性说明:
- 每个文件都可以是一个模块,有自己的作用域。CommonJS 规范规定,每个模块内部,
module
变量代表当前模块,module.exports
是其对外接口。加载某个模块,其实是加载该模块的module.exports
属性。 - 模块可以多次加载,但是只会在第一次加载时运行一次,然后缓存运行结果,以后的加载,就直接读取缓存结果。要想让模块再次运行,必须清除缓存。
- 模块加载的顺序,按照其在代码中出现的顺序。
二、AMD (Asynchronous Module Definition)
CommonJS
规范加载模块是同步的,即加载完成后,才进行后续的操作。而浏览器环境由于资源并不在本地,加载相对 node 环境较慢,因此必须采用非同步的方式。AMD规范使用 define
定义模块,允许非同步加载模块,指定回调函数。
AMD
相关特性:
- 提前声明好依赖
- 模块加载异步,指定回调函数。
引入
其中 CMD 就是兼容 CommonJS 和 AMD 的形式,让开发者可以在浏览器环境中使用 CommonJS 的形式。
CMD 对依赖的模块延迟执行,依赖可就近书写,等到需要时再引入这个依赖。