vue-cli中的CommonsChunkPlugin
下图是使用 vue-cli
构建之后,webpack.prod.conf.js
中有关 CommonsChunkPlugin
的代码块。可以看到 new
了两次 CommonsChunkPlugin
。为什么要 new
两次呢?这两次的作用分别是什么呢?
第一次 new webpack.optimize.CommonsChunkPlugin
webpack
官网对 CommonsChunkPlugin
配置项的解释
{
name: string,
// common chunk的名称
minChunks: number|Infinity|function(module, count){},
// 官方翻译是在传入公共chunk(commons chunk) 之前所需要包含的最少数量的chunks
// 个人理解如果 `number` = 3, 说明被加入到common chunks里的模块要至少被三个chunk或者entries共享
// 传入 `Infinity` 会马上生成 公共chunk,但里面没有模块。
// 可以传入函数,定制自己的逻辑
}
vue-cli
里的 minChunks
使用的是函数模式,那这个函数又代表了什么呢?继续看官网解释。
调用的函数会传入 module
和 count
参数。module
参数代表每个 chunk
里的模块。module
拥有和 NormalModule 类似的特性, 它有两个很有用的属性:
-
module.context
: 保存这个模块的目录. 比如: '/my_project/node_modules/example-dependency' -
module.resource
: 模块真正执行的文件名. 比如: '/my_project/node_modules/example-dependency/index.js'
count
参数表示 module
被使用的 chunk
数量。
接下来看 webpack
配置文件中的第一个 new
:
// 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
// 翻译注释:所有被依赖的模块,如果它在node_modules目录中,都会被抽离出来放进 vendor.js 中
// 如果模块有一个路径,而且在路径中有 js 文件,并且这个模块是属于 node_modules 中的模块
// 那这个模块就会被抽离出来,放进名为 vendor 的这个chunk
return (
module.resource &&
/\.js$/.test(module.resource) &&
module.resource.indexOf(
path.join(__dirname, '../node_modules')
) === 0
)
}
}),
这里,对于 minChunks
传入函数的解释是,如果依赖模块包含路径,而且在路径中有 js
文件,并且这个路径是属于 node_modules
目录的,那这个模块就会被抽离出来,放进名为 vendor
的这个 chunk
。也就是说所有在 package.json
里面依赖的包,都会被打包进 vendor.js
这个文件中。
这样,就可以把依赖的包代码和我们的业务代码分开。如果依赖包不变,每次我们改变业务代码,在构建的时候就不用改变 vendor
里面的内容。浏览器就可以继续使用上一次的缓存。提高加载速度(当然最后打包出来的 chunk
的文件名都是带 hash
的,所以 vendor chunk
最终的文件名会是 vendor.[chunkhash].js
)。
第二次 new webpack.optimize.CommonsChunkPlugin
在 webpack
的 issue
中有一个讨论 #1315。出现的问题是,当只改变业务代码之后打包,不仅 app.[chunkhash].js
的文件名的 chunkhash
变了(业务代码打包进 app.[chunkhash].js
),vendor.[chunkhash].js
的 hash
同样也改变了。这样缓存机制就失去了意义。所以第二次的 new
就是为了解决这个问题的。
会出现这个问题的根本原因是 webpack
在同时使用 [chunkhash]
和代码分割功能的时候会生成 webpack
的 runtime
代码(它主要用来处理代码模块的映射关系),这意味着 [chunkhash]
每次构建都会改变。解决方案就是把这部分的 runtime
代码单独抽离出来生成单独的 chunk
。通过给 CommonsChunkPlugin
传入多个名称来达到这个目的。
// 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']
}),
网友评论