前端模块化实现现状
1. <script> 标签
<script src="module1.js"></script>
<script src="module2.js"></script>
<script src="libraryA.js"></script>
<script src="module3.js"></script>
这个是通过把接口暴露到window全局变量上,其他部分通过闭包来进行封装。
缺点
- 全局变量容易出现冲突
- 只能按script的顺序进行加载
- 开发人员主观来解决依赖关系
- 难管理
- 浏览器一般只能并行load 3-5 个script文件,所以多余6个一般加载会慢
2. CommonJS
服务器端nodejs所遵循的CommonJS规范,通过require和exports来加载和暴露模块,以文件为模块。
在后台中,这和我们大部分时候对nodejs异步处理的印象是不同的,require永远的同步的。
优点
- 便于重用
- 规范
- 易用
- 可用package非常多
缺点
- 同步,不适合浏览器
- 不可以并行的非阻塞的加载多个模块。
实现方式
我经常用的是browserify
AMD
这个主要是为了浏览器端定义的。asynchronous module definition 规范其实只有一个主要接口 define(id?, dependencies?, factory),它要在声明模块的时候指定所有的依赖 dependencies,并且还要当做形参传到 factory 中,对于依赖的模块提前执行,依赖前置。
define("module", ["dep1", "dep2"], function(d1, d2) {
return someExportedValue;
});
require(["module", "../file"], function(module, file) { /* ... */ });
优点
- 优点是适合浏览器异步加载
- 可以多个模块并行加载
缺点
不优雅
实现方式
requrejs
CMD
common module definition 这个规范和 amd相似,同时保持了和nodejs的commonjs规范的兼容性。
define(function(require, exports, module){
var $ = require('jquery');
exports.something = 'hello';
});
优点
- 并行异步加载
- 和nodejs兼容
缺点
需要SPM打包, 逻辑偏重
ES6的模块加载
实现在编译时确认依赖关系,而不是在执行的时候。
import jquery from 'jquery'
export default (n) => {n*3}
优点
- 容易进行静态分析
- 面向未来的es标准
缺点
- 原生的浏览器还没有支持
- 新版的nodejs才支持
实现方式
babel
前端模块加载
前端模块运行在客户的浏览器中,所以需要增量加载到浏览器中。
模块的加载和传输我们首先想到了两种方式 1.每一模块一个请求 2.所有模块一个请求,前者请求连接数太多影响速度,后者第一次加载文件过大,比较慢,初始化时间慢,都比较简单粗暴。
我们想要实现的分块传输,按需进行依赖加载,在实际应用中用到某个模块在增量更新,才是比较合理的。
要实现按需加载,就需要对整个代码进行静态分析和编译打包。
所有的资源都是模块
图片,html模块,css/scss, js 等等其实都是模块,那么我们的实现就非常优雅:
require('./css/custom.scss')
require('./template.jade')
require('./image.png')
这个就是webpack所实现的。