最近读了一下webpack的文档,读到CommonsChunkPlugin这个插件,深深折服于webpack的强大,同时也产生了一些本身的疑问。javascript
首先,CommonsChunkPlugin这个插件是用来提取公共代码的,经过将公共模块提取出来,只在页面加载的时候引入一次,提高应用的加载效率。java
顺便提一下,chunk其实就是代码块的意思,多是一个或多个模块,通常提取后就是一个js文件。node
CommonsChunkPlugin有中文翻译的文档,可是感受并非很通顺,英文文档看完也有一些疑惑,好比minChunks究竟是作什么用的,怎么用?chunks是什么?webpack
首先贴一下文档。web
{ name: "string", names: "string[]", filename: "string", minChunks: "number|Infinity|function(module, count) -> boolean", chunks: "string[]", children: "boolean", async: "boolean|string", minSize: "number" }
entry
中定义,该chunk会被直接提取;若是没有定义,则生成一个空的chunk来提取其余全部chunk的公共代码。output
配置项中文件名的占位符。未定义时使用name
做为文件名。entry
中定义的入口chunk。minChunks:在一个模块被提取到公共chunk以前,它必须被最少minChunks
个chunk所包含(通俗的说就是一个模块至少要被minChunks
个模块所引用,才能被提取到公共模块。)。minChunks参数有三点须要说明:缓存
Infinity
,则建立一个公共chunk,可是不包含任何模块,内部是一些webpack生成的runtime代码和chunk自身包含的模块(若是chunk存在的话)。options.name
的子块和options.chunks
的兄弟块被建立。该chunk会与options.chunks
并行加载。你也可使用该参数指定输出的文件名。咱们看一个简单的例子。app
module.exports = { entry: { app: './src/index.js', vender: [ 'lodash', 'otherlib' ] }, plugins: [ new webpack.optimize.CommonsChunkPlugin({ name: 'vender' }) ], output: { // 使用Hash来命名文件,实现文件缓存的功能。当文件内容发生变化,文件名会随之改变。 filename: '[name].[chunkhash].js', path: path.resolve(__dirname, 'dist') } };
上面的代码中定义了两个入口,app和vender(公共库),plugins中使用CommonsChunkPlugin提取vender。异步
vender是咱们提取出来的公共chunk,一般不会被修改,因此理应在每次编译后文件名保持一致。然而,咱们尝试修改入口文件index.js会发现,vender的文件名会发生变化。async
缘由呢上面提到过,因为每次编译会致使vender的module.id发生变化,内部的runtime代码随之发生改变。ide
解决方案有如下几种:
module.exports = { entry: { app: './src/index.js', vender: [ 'lodash' ] }, plugins: [ new webpack.optimize.CommonsChunkPlugin({ name: 'vender', minChunks: Infinity }), new webpack.optimize.CommonsChunkPlugin({ name: 'manifest', chunks: ['vender'] }) ], output: { filename: '[name].[chunkhash].js', path: path.resolve(__dirname, 'dist') } };
代码中再次使用了CommonsChunkPlugin,从vender中提取出了名为manifest的运行时代码。
Vue在production模式中使用以下配置
// split vendor js into its own file new webpack.optimize.CommonsChunkPlugin({ name: 'vendor', minChunks: function (module, count) { // any required modules inside node_modules are extracted to vendor return ( module.resource && /\.js$/.test(module.resource) && module.resource.indexOf( path.join(__dirname, '../node_modules') ) === 0 ) } }), // extract webpack runtime and module manifest to its own file in order to // prevent vendor hash from being updated whenever app bundle is updated new webpack.optimize.CommonsChunkPlugin({ name: 'manifest', chunks: ['vendor'] })
minChunks配置项有两个参数,module为当前要提取的源chunk中所包含的模块,count表示模块的个数。
自定义函数会被循环调用,直到遍历完全部模块。
module.resource为模块的绝对路径,因此这段代码判断了模块是否在node_modules下,是的话则打包到vender中。
后面一个CommonsChunkPlugin从vender中提取了运行时代码,避免每次打包vender的Hash值都发生变化致使缓存无效。
若有问题,欢迎指正。