pocket-manual
pocket-manual copied to clipboard
Webpack 中 hash、chunkhash 和 contenthash 的区别
使用 Webpack 添加 hash 是实现前端静态资源在浏览器长缓存方案之一。以下介绍一下 Webpack 中 hash、chunkhash 以及 contenthash 的区别:
hash
hash 可以理解是整个项目的 hash 值,其根据每次编译 compilation 的内容计算得到,每次编译之后都会生成新的 hash,即修改任何文件都会导致所有文件的 hash 发生改变:
output: {
filename: '[name].[hash].js',
path: path.join(__dirname, 'dist')
}
所以使用 hash 无法实现前端静态资源在浏览器上长缓存,这时候应该使用 chunkhash。
chunkhash
chunkhash 根据不同的入口文件(entry)进行依赖文件解析,构建对应的 chunk,生成相应的 hash:
output: {
filename: '[name].[chunkhash].js',
path: path.join(__dirname, 'dist')
}
所以每次编译之后,每个 chunk 的 hash 都是不同的。对于每个 chunk 来说,如果该 chunk 代码不变,那么 hash 也将保持不变,从而实现该资源在浏览器上长缓存。
例如,由于公共库基本上不会随意改动,我们可以把公共库(vendor)和入口文件区分开,使用 chunkhash:
entry: {
app: path.join(__dirname, 'src/index.js'),
vendor: ['vue']
},
output: {
filename: '[name].[chunkhash].js',
path: path.join(__dirname, 'dist')
}
但是,使用 chunkhash 存在一个问题:当在一个 JS 文件中引入了 CSS 文件,编译后它们的 hash 是相同的。而且,只要 JS 文件内容发生改变,与其关联的 CSS 文件 hash 也会改变。
针对这种情况,可以把 CSS 从 JS 中抽离出来并使用 contenthash。
contenthash
使用 mini-css-extract-plugin 或 extract-text-webpack-plugin 把 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: '[name].[contenthash].css'
})
]
}