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…
发表回复