webpack中的hash、chunkhash和contenthash
这三个hash值都是webpack在打包的时候根据内部算法生成的一串字符串,总的来说最大的不同就是其囊括控制的范围大小不同,对应的控制颗粒度不同。
hash
hash是对webpack整个一次构建而言,在webpack构建中,文件都会带上对应的MD5值,构建生成的文件hash值都是一样的。如果出口是hash,那么一旦针对项目中任何一个文件的修改,都会构建整个项目,重新获取hash值。如果有目的性的缓存就会失败。
chunkhash
chunkhash的范围可以针对某个模块而言,它会从入口出发,对依赖文件进行解析,构建对应的chunk和hash值。一般的使用是在生产环境对公共库和程序入口文件单独抽离开,单独打包构建,用chunkhash的方式对这些打包后的文件带上相应hash值。在线上,只要公共库和入口没变,其hash值就不会改变,从而达到缓存的目的。
eg:
entry:{
main: path.join(__dirname,'./main.js'),
vendor: ['vue']
},
output:{
path:path.join(__dirname,'./dist'),
publicPath: '/dist/',
filname: 'bundle.[chunkhash].js'
}
此时入口有两个,main和vendor,此时的打包就会生成main和ventor两个hash值,这两个hash值是分别以main和vendor为入口出发根据依赖文件构建生成的chunk和hash值。(chunk可以理解为入口+他依赖的文件构成的模块)
contenthash
contenthash的范围更具体和更小,即对某一个文件而言,在webpack中的用法一般是分离js和css,单对css文件来设置。因为上面的chunkhash存在一个问题:
chunkhash以入口和依赖文件构建的chunk模块,只要对应其中一个css或则js改变,与其关联的文件hash值也会改变,但其他内容并没有改变,一定意义上的缓存也就失效。
比如我js文件逻辑改变了,但是我css样式并没有改动,css文件就应该从缓存中加载,不应该从服务器中重新获取,浪费带宽和性能。
所以在项目中,通常做法是把项目中css都抽离出对应的css文件来加以引用。
比如使用mini-css-extract-plugin:
const miniCssExtractPlugin=require("mini-css-extract-plugin");
module.exports={
module:{
rules:[
{
test: /\.css$/,
use:[
miniCssExtractPlugin.loader,
'css-loader'
]
}
]
},
plugins:[
new miniExtractPlugin({
filename: 'main.[contenthash:7].css'
})
}
}
main模块用了chunkhash,这里单独把main的css抽离出来用contenhash处理,打包后即使css文件所处的模块里就算其他文件内容改变,只要css文件内容不变,那么就不会重复构建。