赞
踩
伴随着移动互联的大潮,当今越来越多的网站已经从网页模式进化到了 Webapp 模式。它们运行在现代的高级浏览器里,使用 HTML5、 CSS3、 ES6等更新的技术来开发丰富的功能,网页已经不仅仅是完成浏览的基本需求,并且webapp通常是一个单页面应用,每一个视图通过异步的方式加载,这导致页面初始化和使用过程中会加载越来越多的JavaScript 代码,这给前端开发的流程和资源组织带来了巨大的挑战。
前端开发和其他开发工作的主要区别,首先是前端是基于多语言、多层次的编码和组织工作,其次前端产品的交付是基于浏览器,这些资源是通过增量加载的方式运行到浏览器端,如何在开发环境组织好这些碎片化的代码和资源,并且保证他们在浏览器端快速、优雅的加载和更新,就需要一个模块化系统,这个理想中的模块化系统是前端工程师多年来一直探索的难题。
前端模块要在客户端中执行,所以他们需要加载到浏览器中。模块的加载和传输,我们首先能想到两种极端的方式,一种是每个模块文件都单独请求,另一种是把所有模块打包成一个文件然后只请求一次。显而易见,每个模块都发起单独的请求造成了请求次数过多,导致应用启动速度慢;一次请求加载所有模块导致流量浪费、初始化过程慢。这两种方式都不是好的解决方案,它们过于简单粗暴。分块传输,按需进行懒加载,在实际用到某些模块的时候再增量更新,才是较为合理的模块加载方案。
<script src="module1.js"></script>
<script src="module2.js"></script>
<script src="module3.js"></script>
这是最原始的 JavaScript 文件加载方式,如果把每一个文件看做是一个模块,那么他们的接口通常是暴露在全局作用域下,也就是定义在 window 对象中,不同模块的接口调用都是一个作用域中,一些复杂的框架,会使用命名空间的概念来组织这些模块的接口,典型的例子如 YUI 库。
缺点:
<script>
的书写顺序进行加载服务器端的 Node.js 遵循 CommonJS规范,该规范的核心思想是允许模块通过 require 方法来同步加载所要依赖的其他模块,然后通过 exports 或 module.exports 来导出需要暴露的接口。CommonJS规范
// moduleA.js
module.exports = function( value ){
return value * 2;
}
// moduleB.js
var multiplyBy2 = require('./moduleA');
var result = multiplyBy2(4);
优点:
缺点:
实现:
补充,exports与module.exports区别:
为了方便,Node为每个模块提供一个exports变量,指向module.exports。var exports = module.exports;造成的结果是,在对外输出模块接口时,可以向exports对象添加方法。
exports.area = function (r) {
return Math.PI * r * r;
};
注意,不能直接将exports变量指向一个值,因为这样等于切断了exports与module.exports的联系。
exports = function(x) {console.log(x)};
下面的写法也是无效的。
exports.hello = function() {
return 'hello';
};
module.exports = 'Hello world';
上面代码中,hello函数是无法对外输出的,因为module.exports被重新赋值了。这意味着,如果一个模块的对外接口,就是一个单一的值,不能使用exports输出,只能使用module.exports输出。
module.exports = function (x){ console.log(x);};
如果你觉得,exports与module.exports之间的区别很难分清,一个简单的处理方法,就是放弃使用exports,只使用module.exports。
AMD 定义了一套 JavaScript 模块依赖异步加载标准,来解决同步加载的问题。https://github.com/amdjs/amdjs-api/wiki/AMD
define(id?: String, dependencies?: String[], factory: Function|Object);
define(function(require, exports, module) {})
define("module", ["dep1", "dep2"], function(d1, d2) {
return someExportedValue;
});
注意:主模块module是在dep1、dep2加载完成并执行结束后才执行,即使处理函数中没有用到这两个模块,dep1、dep2一旦被依赖引用就会被加载执行!
require(["module", "../file"], function(module, file) { /* ... */ });
在模块定义内部引用依赖:
define(function(require) {
var $ = require('jquery');
$('body').text('hello world');
});
优点:
缺点:
实现:
CMD规范和AMD很相似,尽量把持简单,并与 CommonJS 和 Node.js 的 Modules 规范保持了很大的兼容性。遵循按需执行依赖的原则,只有在用到某个模块的时候才会执行模块内部的require语句,同时加载完某个依赖文件后并不立即执行,在所有依赖模块加载完成后进入主模块逻辑,遇到模块运行语句的时候才执行对应的模块https://github.com/seajs/seajs/issues/242
define(function(require, exports, module) {
var $ = require('jquery');
var Spinning = require('./spinning');
exports.doSomething = ...
module.exports = ...
})
优点:
缺点:
实现:
EcmaScript6 标准增加了 JavaScript 语言层面的模块体系定义。ES6 模块的设计思想,是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。CommonJS 和 AMD 模块,都只能在运行时确定这些东西。
import "jquery";
export function doStuff() {}
module "localModule" {}
优点:
缺点:
实现:
补充:
Webpack中提出了tree-shaking,其依赖ES6 modules的静态特性得以实现,ES6 modules 的 import 和 export statements相比完全动态的CommonJS、require,有着本质的区别:
注意:Babel 6的规范选择是使用预设es2015
:
{
presets: ['es2015'],
}
但是,该预设包含插件transform-es2015-modules-commonjs
,这意味着Babel会输出CommonJS模块,而webpack将无法进行tree-shaking。想要的是Babel的es2015
,但没有插件transform-es2015-modules-commonjs
。目前,唯一的办法就是提到配置数据中的所有预置插件,除了我们要排除的插件。预设的来源是GitHub,所以基本上是复制和粘贴的情况:
{
plugins: [
'transform-es2015-template-literals',
'transform-es2015-literals',
'transform-es2015-function-name',
'transform-es2015-arrow-functions',
'transform-es2015-block-scoped-functions',
'transform-es2015-classes',
'transform-es2015-object-super',
'transform-es2015-shorthand-properties',
'transform-es2015-computed-properties',
'transform-es2015-for-of',
'transform-es2015-sticky-regex',
'transform-es2015-unicode-regex',
'check-es2015-constants',
'transform-es2015-spread',
'transform-es2015-parameters',
'transform-es2015-destructuring',
'transform-es2015-block-scoping',
'transform-es2015-typeof-symbol',
['transform-regenerator', { async: false, asyncGenerators: false }],
],
}
Webpack 是一个前端资源模块化管理和打包工具。它将根据模块的依赖关系进行静态分析,然后将这些模块按照指定的规则生成对应的静态资源。还可以将按需加载的模块进行代码分隔,等到实际需要的时候再异步加载。通过 loader 的转换,任何形式的资源都可以视作模块,比如 CommonJs 模块、 AMD 模块、 ES6 模块、CSS、图片、 JSON、Coffeescript、 LESS 等。
优点:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。