1 概述
1.1 前端为什么须要模块化
- 解决命名抵触
- 提供代码复用性和可维护性
- 灵便架构,焦点拆散,不便模块间组合、合成
- 多人合作互不烦扰
1.2 js 模块化倒退历程
1.2.1 script 标签
随着前端复杂度进步,为什么可能进步我的项目代码的复用性和可维护性等,就将一个性能封装成一个文件,把一个 js 文件当成一个模块,这样 js 文件也就多了起来。js 引入形式大略是上面这样:
<script src="jquery.js"></script>
<script src="jquery_scroller.js"></script>
<script src="main.js"></script>
<script src="other1.js"></script>
<script src="other2.js"></script>
<script src="other3.js"></script>
简略的将 js 文件放在一起,然而彼此的援用程序不能出错。比方必须先引入 jquery,能力应用 jquery_scroller,不然就会报错
长处:
绝对于所有逻辑都在同一个 js 文件,模块化思维是提高的。
毛病:
净化全局作用域。因为每一个都是裸露在全局的,会导致全局变量命名抵触,可通过命名空间解决
依赖关系不显著,不利于保护。比方 main.js 须要应用 jquery,然而,从下面的文件中,咱们是看不出来的,如果 jquery 遗记了,那么就会报错。
1.2.2 CommonJS 标准
CommonJS 标准是一个对 js 模块化的标准,最后用在服务端 node 上。webpack 是反对 CommonJS 标准的。
依据标准,每一个文件都是模块,其外部定义的变量属于这个模块,不会对外裸露,即不会净化全局变量。中心思想是通过 require 办法同步加载所依赖的模块,而后通过 exports 或者 module.exports 来导出须要裸露的接口。如下所示:
// a.js
var x = 5;
var addX = function (value) {return value + x;};
module.exports.x = x;
module.exports.addX = addX;
//b.js
var a = require('./a.js');
console.log(example.x); // 5
console.log(example.addX(1)); // 6
这里的 a.js 就是 CommonJS 标准的模块了。module 代表这个模块,exports 属性就是对外裸露的接口,能够对外导出可拜访的变量和办法,比方 x 和 addX
exports 是对 module.exports 的援用,所以咱们能够认为模块顶部有 exports = module.exports 这样一个定义,所以咱们不能间接给 exports 赋值
这样咱们在 b.js 中就能获取到 a.js 裸露的变量和办法
长处:
解决了依赖和全局变量净化的问题
毛病:
因为 CommonJS 是同步加载的,服务器端没有问题,然而在浏览器端须要将文件从服务器端申请过去,只有加载实现能力执行前面的操作,会阻塞渲染,所以不实用在浏览器端
1.2.3 AMD 标准
AMD 标准是非同步加载模块,容许指定回调函数。AMD 标准的实现就是 require.js
AMD 规范中定义了上面两个 api
- require([module], callback)
- define(id, [depends], callback)
即通过 define 定义一个模块,而后应用 require 来加载一个模块,并且 require 还反对 CommonJS 的导出形式
定义 alert 模块:
define(function () {var alertName = function (str) {alert("I am" + str);
}
var alertAge = function (num) {alert("I am" + num + "years old");
}
return {
alertName: alertName,
alertAge: alertAge
};
});
引入模块:
require(['alert'], function (alert) {alert.alertName('zhansan');
alert.alertAge(18);
});
长处:
反对浏览器环境异步加载模块,能够并行加载多个模块
毛病:
进步了开发成本,并且不能按需加载,必须提前加载所有的依赖
1.2.4 CMD 标准
CMD 和 AMD 相似,即一个 js 文件就是一个模块,然而 CMD 是按需加载,不是在模块开始加载所有的依赖,如下所示:
define(function(require, exports, module) {var $ = require('jquery');
var Spinning = require('./spinning');
exports.doSomething = ...
module.exports = ...
})
长处:
实现了浏览器端的模块话加载
按需加载,依赖就近
毛病:
依赖 SPM 打包,模块的加载逻辑并重。
这时咱们就能够看出 AMD 和 CMD 的区别了,前者是对于依赖的模块提前执行,而后者是提早执行。前者推崇依赖前置,而后者推崇依赖就近,即只在须要用到某个模块的时候再 require。如下:
// AMD
define(['./a', './b'], function(a, b) { // 依赖必须一开始就引入
a.doSomething()
b.doSomething()
//...
});
// CMD
define(function(require, exports, module) {var a = require('./a')
a.doSomething()
var b = require('./b')
// 依赖能够就近引入
b.doSomething()
// ...
});
1.2.5 ES6 模块化
ES6 模块化计划是真正的标准,下面的几种计划只是前段社区本人实现的。在 ES6 中,通过 import 关键字引入模块,export 关键字导出模块。ES6 模块化和 CommonJs 的一个区别就是前者导入导出都是援用,而后者导入的是值的拷贝。
/**
* 首字母大写
* @param str
*/
export const capitalize = (str: string) => {
str = str || '';
if (str.length > 0) {const first = str.substr(0, 1).toUpperCase();
const spare = str.substr(1, str.length);
return first + spare;
}
};
2. 打包工具
2.1 Webpack
webpack 能够看做是模块打包机:它做的事件是,剖析你的我的项目构造,找到 JavaScript 模块以及其它的一些浏览器不能间接运行的拓展语言(Scss,TypeScript 等),并将其转换和打包为适合的格局供浏览器应用。
长处:
所有皆模块,能够模块化任何资源
反对各种模块化语法
开发便捷
扩展性强,插件机制欠缺
毛病:
配置简单,文档滞后
通过 babel 编译之后的 js 代码打包后体积过大
2.2 Parcel
超快的打包速度,多线程在多核上并发编译,不必任何配置。
长处:
能做到无配置实现以上我的项目构建要求;
内置了常见场景的构建计划及其依赖,无需再装置各种依赖;
能以 HTML 为入口,自动检测和打包依赖资源;
默认反对模块热替换,真正的开箱即用;
毛病:
不反对 SourceMap
不反对剔除有效代码 (TreeShaking)
一些依赖会 让 Parcel 出错:当你的我的项目依赖了一些 Npm 上的模块时,有些 Npm 模块会让 Parcel 运行谬误;
不灵便的配置,无奈自定义
如图:
参考如下:
https://zhuanlan.zhihu.com/p/…
https://blog.csdn.net/github_…
https://segmentfault.com/a/11…