Code splitting
对于大型Web应用程序,将所有代码放入单个文件并不高效,尤其是在某些情况下只需要某些代码块的情况下;
Webpack有一个功能,将代码库拆分为“chunks”,并根据需要加载;
当然,这是可选的功能,由开发者自己在代码中定义拆分点, Webpack负责依赖关系,输出文件和运行;
代码分割不仅仅是将通用的代码提取到公共Chunks中。更显着的特征是代码拆分可以用于将代码拆分为按需加载的块——这可以保证初始下载的代码很小,并在应用程序请求时按需下载代码;
实现Code splitting,需要定义模块(这里讲解CommonJS 和AMD规范),并按需加载(CommonJS和AMD对应的引入方法);
CommonJS && AMD
AMD和CommonJs指定不同的方法来按需加载代码:
1. 定义模块
CommonJS && AMD都是通过定义一个规范来实现JavaScript模块化,确保每一个模块只能在其命名空间里执行,以此来解决JavaScript的作用域问题(封装、局部作用域);
都是强制模块明确输出一个值(object | function),使引入它的其它模块能够调用该模块明确输出的值(object | function);
A文件引入B文件:
require("B")
,才能实现在A的作用范围中可以调用B模块明确输出的值(object | function),否则直接调用B模块返回值=>undefined;
CommonJS定义模块
同步引入依赖,多用于Server;
-
CommonJS提供两个规范:
require() 函数引入一个已有模块到当前作用域(若实现code splitting,我们不用这个函数);module对象,用于定义模块中,允许开发者在当前作用域下输出一些东西;
示例1:
//输出一个变量值;
var MySalute = "Hello";
module.exports = MySalute;
示例2:
//输出一个函数;
module.exports = function( value ){
return value*2;
}
AMD定义模块
异步引入依赖,多用于Browser Client;
通过define()函数来定义模块;
define(id?: String, dependencies?: [], factory: Function|Object);
id可选项,定义模块名称,期望类型:字符串;dependencies可选项,定义模块依赖,期望类型:数组( 如果被忽略,默认是[“require”, “exports”, “module”]);factory必选项,定义模块输出;
2. 实现code splitting,不同模块规范相应的模块引用
CommonJS 与webpack实现按需加载
require.ensure(dependencies?[], callback)
require.ensure方法确保在指定依赖库里的每一个依赖能被同步加载;
callback没有参数;
-
注意: require.ensure只是加载模块,并没有计算该模块的输出表达式,需要在callback中再次调用以此;
示例: require.ensure(["module-a", "module-b"], function() {
var a = require("module-a");
// ...
//这时,module-a,module-b会与该模块打成一个包;});
AMD 与webpack实现按需加载
require(dependencies, callback)
-
注意:AMD规范与CommonJS不同, AMD require加载并计算依赖,输出的结果按依赖顺序为callback的参数;
示例: require(["module-a", "module-b"], function(a, b) { // ... //function()中的a相当于module-a中的输出; //b相当于module-b中的输出,顺序要对应; });
3. webpack
运行webpack进行打包,您会看到出现多个0.bundle.js,1.bundle.js,2.bundle.js...
多个Chunks对应多个js文件;
浏览器请求时,只返回入口文件,条件满足时通过require依赖,请求其它依赖文件;
多余的话:webpack是NodeJS模块,为CommonJS规范,所以我们常用引入依赖的方法是require(),注意,这不是实现代码分割的require.ensure();
这时候,我们已经实现了Code splitting,下边的内容主要介绍webpack定义且分离出来的不同类型的Chunks,并对Chunks进行优化;
Chunks
Entry chunk
Webpack打包时会给入口文件(Entry chunk)添加runtime,来标识着从该文件开始查找依赖并执行;
一个入口文件(Entry chunk)包含runtime和一系列初始化模块;如果入口文件包含模块0,则运行时执行它。如果不包含,它等待包含模块0的块并执行它。
一个页面只能包含一个runtime,即只能包含一个入口文件(可以通过Optimization来提取入口文件中的公用runtime,实现多入口点);
Normal chunk
一个普通的chunk不包含runtime,只是code splitting分割出来的依赖模块打成的包;如上文中的:
示例:
require.ensure(["module-a", "module-b"], function() {
var a = require("module-a");
// ...
//该模块被require.ensure()后会打包成normal chunk。
});
Initial chunk (non-entry)
Initial chunk是normal chunk的一种;
它是通过Optimization优化(CommonsChunkPlugin)得到的;
它被计入初始化时间;
Running multiple entry points
一个Page只能包含一个runtime(webpack打包时生成的Header);
CommonsChunkPlugin在参数不指定Chunks的时候
plugins: [ new webpack.optimize.CommonsChunkPlugin("init.js") ]
,会提取所有chunks公共部分生成一个chunk(CommonsChunkPlugin必然提取了所有entry chunks中的runtime,则其它entry chunks不含runtime,从而变成了initial chunks );
对于大型Web应用程序,在开发过程中可能会产生太多小型的Chunks,这样会造成更大的HTTP开销,此时,需要考虑Chunks优化;
Optimization
压缩代码
new webpack.optimize.UglifyJsPlugin()
针对Chunks优化
在编写和打包代码时,你可能会注意到,有太多太小的Chunks,会产生更大的HTTP开销,此时,可以考虑如下的优化:
限制最大chunk数量:
new webpack.optimize.LimitChunkCountPlugin({maxChunks: 15})
限制最小chunk大小:
new webpack.optimize.MinChunkSizePlugin({minChunkSize: 10000})
以上是参考webpack1的版本进行的说明,2的版本还没有关注,尽请见谅;
这里也没有涉及到ES6、7,见谅见谅;
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。