重新打包之后你会发现打包结果中多出一个1.mian.js,这里面就是将来会被异步加载进来的内容。刷新页面并查看chrome的network标签,可以看到页面会请求1.main.js。它并不来源于index.html中的引用,而是通过main.js在页面插入了script标签来将其引入的。
使用webpack的构建特性
从2.0.0版本开始,webpack开始加入了更多的可以优化构建过程的特性。
tree-shaking
在关于模块的那一篇文章中我们提到过,ES6 Module的模块依赖解析是在代码静态分析过程中进行的。换句话说,它可以在代码的编译过程中得到依赖树,而非运行时。利用这一点webpack提供tree-shaking功能,它可以帮助我们检测工程中哪些模块有从未被引用到的代码,这些代码不可能被执行到,因此也称为“死代码”。通过tree-shaking,webpack可以在打包过程中去掉这些死代码来减小最终的资源体积。
开启tree-shaking特性很简单,只要保证模块遵循ES6 Module的形式定义即可,这意味着之前所有我们的例子其实都是默认已经开启了的。但是要注意如果在配置中使用了babel-preset-es2015或者babel-preset-env,则需要将其模块依赖解析的特性关掉,如:
presets: [ [env, {module: false}] ]
这里我们测试一下tree-shaking的功能,编辑module.js:
// module.js export const log = function() { console.log('module.js loaded.'); } export const unusedFunc = function() { console.log('not used'); }
打开页面查看1.main.js的内容,应该可以发现unusedFunc的代码是不存在的,因为它没有被别的模块使用,属于死代码,在tree-shaking的过程中被优化掉了。
tree-shaking最终的效果依赖于实际工程的代码本身,在我对于实际工程的测试中,一般可以将最终的体积减小3%~5%。总体来看,我认为如果要使tree-shaking发挥真正的效果还要等几年的时间,因为现在大多数的npm模块还是在使用CommonJS,因此享受不了这个特性带来的优势。
scope-hoisting
scope-hoisting(作用域提升)是由webpack3提供的特性。在大型的工程中模块引用的层级往往较深,这会产生比较长的引用链。scope-hoisting可以将这种纵深的引用链拍平,使得模块本身和其引用的其它模块作用域处于同级。这样的话可以去掉一部分 webpack的附加代码,减小资源体积,同时可以提升代码的执行效率。
目前如果要开启scope-hoisting,需要引入它的一个内部插件:
module.exports = { plugins: [ new webpack.optimize.ModuleConcatenationPlugin() ] }
scope-hoisting生效后会在bundle.js中看到类似下面的内容,你会发现log 的定义和调用是在同一个作用域下了:
// CONCATENATED MODULE: ./module.js const log = function() { console.log('module.js loaded.'); } // CONCATENATED MODULE: ./app.js log();