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,见谅见谅;


米花儿团儿
1.3k 声望75 粉丝

« 上一篇
React-intl