原创翻译,转载请注明出处。
原文地址:https://webpack.js.org/guides/code-splitting/
一个典型的应用基于框架或者功能的需求,会依赖于许多第三方库。会使用这些库的特定版本,代码不会频繁变更。相对比,应用的代码会频繁变更。
连同第三方库的代码一起打包应用代码会非常低效。这是因为会基于缓存头部信息来缓存资源文件,并且缓存的文件如果内容没有变更,就不需要访问cdn。要想利用这个优点,我们希望不管应用代码如何变化,第三方库文件的哈希值保持不变。
只有我们把第三方库文件和应用代码分开打包才能实现。
让我们考虑一个使用momentjs的简单应用,一个通常用于时间格式化的库。
在你的应用文件夹上,像下面这样安装moment。
npm install --save moment
index文件将会当作一个依赖来引入moment,并且像下面这样输出当前时间的日志
index.js
var moment =require('moment'); console.log(moment().format());
我们可以使用下面的配置,用webpack打包应用
Webpack.config.js
var path =require('path'); module.exports =function(env){ return{ entry:'./index.js', output:{ filename:'[name].[chunkhash].js', path: path.resolve(__dirname,'dist') } } }
在你的应用里运行webpack,如果你检查结果包,你将会看到moment和index.js被打包到bundle.js里。
多个入口
让我们为moment增加独立的入口点来避免这个结果,命名它为vendor
webpack.config.js
var path =require('path'); module.exports =function(env){ return{ entry:{ main:'./index.js', vendor:'moment' }, output:{ filename:'[name].[chunkhash].js', path: path.resolve(__dirname,'dist') } } }
现在运行webpack,我们看到生成了两个包。如果你已经检查过它们,你会发现moment代码出现在两个包文件里!原因时moment是主应用(例如:index.js)的依赖,并且每一个入口点都会打包他们的依赖。
正是这个原因,我们需要使用CommonsChunkPlugin。
CommonsChunkPlugin
这是一个相当复杂的插件。它从根本上允许我们从不同的包里提取出共同模块,把它们加到共通包里。如果共通包不存在就做成一个新的。
我们可以像下面这样修改webpack配置文件:
webpack.config.js
var webpack =require('webpack'); var path =require('path'); module.exports =function(env){ return{ entry:{ main:'./index.js', vendor:'moment' }, output:{ filename:'[name].[chunkhash].js', path: path.resolve(__dirname,'dist') }, plugins:[ newwebpack.optimize.CommonsChunkPlugin({ name:'vendor'// Specify the common bundle's name. }) ] } }
现在在你的应用里运行webpack。查看包的内容会发现moment代码只存在与vendor包里。
默认的共通第三方库代码块
你可以配置CommonsChunkPlugin实例让他们只处理第三方库。
webpack.config.js
var webpack =require('webpack'); var path =require('path'); module.exports =function(){ return{ entry:{ main:'./index.js' }, output:{ filename:'[name].[chunkhash].js', path: path.resolve(__dirname,'dist') }, plugins:[ newwebpack.optimize.CommonsChunkPlugin({ name:'vendor', minChunks:function(module){ // this assumes your vendor imports exist in the node_modules directory return module.context && module.context.indexOf('node_modules')!==-1; } }) ] }; }
清单文件
但是如果我们修改应用代码,并重新运行webpack,我们发现三方库文件的哈希值变了。虽然我们做成了分开的vendor和main包,我们看到应用代码变化的时候,vendor包也随着变化。这意味着我们仍然不能利用浏览器的缓存这个优点,应为vendor文件的哈希值会随着每次编译而变化,这样的话浏览器将不得不再次加载文件。
这个问题存在于每一次编译里,webpack生成一些webpack运行时代码,它帮助webpack完成它的工作。当只有一个包的时候,运行时代码就会存在于这个包里面。当有多个包生成的时候,运行时代码就会被提取到共通模块里,这里的vendor文件。
为了防止这个,我们需要把运行时代码提取到一个独立的清单文件里。虽然我们多生成了一个包,这个缺点将会被我们得到的vendor文件的长期缓存优点抵消。
webpack.config.js
var webpack =require('webpack'); var path =require('path'); module.exports =function(env){ return{ entry:{ main:'./index.js', vendor:'moment' }, output:{ filename:'[name].[chunkhash].js', path: path.resolve(__dirname,'dist') }, plugins:[ newwebpack.optimize.CommonsChunkPlugin({ names:['vendor','manifest']// Specify the common bundle's name. }) ] } };
通过上面的webpack配置,我们看到生成了3个包文件。vendor,main和manifest包。
-- End --