1.上一节说到为了降低网络流量,浏览器会有缓存机制。如果说我们以原输出文件名不变的情况下,将资源挂在到服务器上面,实际上,服务器实际会优先使用他的缓存文件,这就是所谓的命中缓存。
如果能够分门别类的按需缓存是最好的了,一些文件经常性的修改,这些资源就不能缓存,而一些外部的依赖包的话,例如loadsh这些库文件是可以缓存的。
那么咋们怎么实现这些需求呢?
1.1咋们首先实现全部所有文件的不缓存。
实现为hash命名的方式。实际上如果有了解的话,应该知道在网页的url后面添加一段随机的hash字符串能够避免游览器的缓存。其实简单的理解就是告诉浏览器重新认识我一下,我已不是从前的我了。
在package.json文件中配置输出文件名以chunkhash形式输出。
module.exports = [
...
output: {
path: path.resolve(__dirname, 'dist'),
publicPath: "",
filename: '[name].[hash].js'
}
}
然后两次运行npm run build,同一文件夹的名字输出为:
第一次:index1.38646ec366d44b359a25.js。
第二次:index1.38646ec366d44b359a25.js。
是一样的。
然后,我分别注释和解一段index.js的代码后,输出文件名:
注释:index1.814f751b33a71607a436.js。
解注释:index1.38646ec366d44b359a25.js。
竟然能够区分出两次相同代码的文件。webpack牛逼。
1.2 实现了文件的hash命名自然能够避免文件修改后的同样命中缓存。但是某些文件我们希望它能够被缓存,比如比较大的依赖库文件。
官方给了以下解决方案,结合内部插件CommonsChunkPlugin以及HashedModuleIdsPlugin实现vendor(被CommonsChunkPlugin抽离的公共的js文件)被浏览器命中缓存。
在webpack.config.js中配置:
const webpack = require('webpack');
module.exports={
...
entry: {
main: './src/index.js',
// 需要打包为缓存项的chunks
vendor: [
'lodash'
]
},
output: {
path: path.resolve(__dirname, 'dist'),
publicPath: "",
filename: '[name].[hash].js'
},
// 以下方法已被废弃
// plugins: [
// ....
// //libs
// new webpack.optimize.CommonsChunkPlugin({
// name: 'vendor'
// }),
// //模块关系管理文件
// new webpack.optimize.CommonsChunkPlugin({
// name: 'manifest'
// })
// ]
// 新的配置方法
optimization: {
splitChunks: {
cacheGroups: {
commons: {
// loadsh库
name: "vendor",
chunks: "initial",
minChunks: 2
}
}
},
splitChunks: {
cacheGroups: {
commons: {
// 描述文件模块加载关系
name: "manifest",
chunks: "initial",
minChunks: 2
}
}
}
}
}
...
npm run build后发现dist下生成图1-1所示的文件:
更改index.js中代码后dist下如图1-2;
可以看到index1、manifest、vendor文件的hash值都变了,输出bundle变化原因如下:
1.index文件内容修改后hash会变化;
2.vendor文件因为module.id变化而后hash变化;
3.index、vendor文件hash变化造成模块引用关系变化而导致manifest变化。
这样其实不符合我们代码分离的预期。实际上我们只希望在为变动文件依赖关系的情况下只有index1文件的hash值变化。
1.3 那么为什么会出现以上这种情况呢?
那么要搞清楚hash
,chunkhash
,contenthash
的区别了:
- hash是只要有文件改变,所有文件hash都会改变。
- chunkhash是同一chunk下的文件有改变,chunk下的文件hash都会变动。
- contenthash是当前文件内容变化,当前文件的hash变化。
具体可以参考这篇文章 webpack:hash、chunkhash、contenthash三者区别
注意: 此处不要是同filename不要使用[name].[hash].js,应该使用[name].[contenthash].js,并且切要确保热替换不在产品环境下运行。改配置:
我们这里用contenthash:
output: {
path: path.resolve(__dirname, 'dist'),
publicPath: "",
filename: '[name].[contenthash].js'
},
修改文件多次npm run build运行后发现dist下只有index文件的hash值随更改变化。
本文为学习文档,仅供个人学习。