我们常常需要在浏览器缓存一些稳定的资源,如第三方库等。要达到这个目标,只需要两步:
1、提取出“稳定的资源”;
2、提供稳定的文件hash 。
webpack中提取公共模块一般使用 webpack 内置的 CommonsChunkPlugin 插件,他可以提取出 入口chunk中 的公共模块:
1、minChunks 参数 是指 至少有minChunks个入口引用的模块才会提取出来,infinity等于入口数量,即所有入口都引用的模块才会提取出来;
上面的例子是一个SPA,入口是main.js。为了提取出第三方库,我们新增一个vendors入口中,并引入所有用到的第三方库,就像这样:
里面并没有业务代码,vendors文件只是为了引导CommonsChunkPlugin插件提取出 第三方库!
2、names 参数 传入数组,等效于 : (文档的描述是:" 一个字符串数组被传入,这相当于插件针对每个 chunk 名被多次调用"
)
其中,从vendors中提取manifest 的操作,我查看vue-cli的配置,里面的注释是这样的 :
“extract webpack runtime and module manifest to its own file in order to prevent vendor hash from being updated whenever app bundle is updated”,
文档解释:
" 但是,如果我们改变应用的代码并且再次运行 webpack
,可以看到 vendor 文件的 hash 改变了。即使我们把 vendor
和 main
的 bundle 分开了,也会发现 vendor
bundle 会随着应用代码改变。
这意味着我们任然无法从浏览器缓存机制中受益,因为 vendor 的 hash 在每次构建中都会改变,浏览器也必须重新加载文件。
这里的问题在于,每次构建时,webpack 生成了一些 webpack runtime 代码,用来帮助 webpack 完成其工作。当只有一个 bundle 的时候,runtime 代码驻留在其中。但是当生成多个 bundle 的时候,运行时代码被提取到了公共模块中,在这里就是 vendor
文件。
为了防止这种情况,我们需要将运行时代码提取到一个单独的 manifest 文件中。尽管我们又创建了另一个 bundle,其开销也被我们在 vendor
文件的长期缓存中获得的好处所抵消。"
,大意就是,如果不把manifest提取出来,只要业务代码有改动,
vendors(存放提取出来的第三方库)文件的内容也会变化,即它的chunkhash也会改变,这不是我们想要的!
3、hash 与 chunkhash:
[ hash ]是webpack编译的hash值,每次编译都不一样;[ chunkhash ]则是根据文件内容计算所得的hash值,文件内容不变的话,这个值是固定的。
用webpack构建时,默认是css in js的,即css包含在js内,webpack计算chunkhash时,整个chunk的内容会将css的内容也计算在内。所以,不论是修改了js代码还是css代码,整个chunk的内容都改变了,计算所得的chunkhash随之改变。
但理想情况下是想css或js内容改变时仅影响自身文件的chunkhash,这样客户端只需更新一部分文件。解决此问题首先要将css单独编译输出文件,并给他一个独立的extracttextplugin插件提供的 [ contenthash ] -- 根据文本内容生成的hash值。
把css提取出来后,就可以吧css单独缓存了!