webpack中fullhash、chunkhash和contenthash的区别
hash通常被作为前端静态资源实现增量更新的方案,通过在文件名中带上一串hash字符串,告诉浏览器该文件是否发生更新,从而决定是否要使用缓存机制。
webpack打包时的hash有三种:fullhash
(webpack4.x版本及之前为 hash,webpack5.x中使用 fullhash 和 hash 均可)、chunkhash
和 contenthash
,那么他们之间有什么区别呢,下面我们一起来看下。
项目结构
我们有如下的一个目录结构:
hash
├─ package.json
├─ src
│ ├─ add.js
│ ├─ index.css
│ ├─ index.js
│ └─ sub.js
├─ webpack.config.js
└─ yarn.lock
webpack.config.js
webpack.config.js 配置如下:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
/**
* @type {import('webpack').Configuration}
*/
module.exports = {
entry: {
index: './src/index.js',
add: './src/add.js',
sub: './src/sub.js',
},
mode: 'production',
output: {
path: path.resolve(__dirname, './dist'),
filename: '[name].[fullhash].js',
clean: true,
},
module: {
rules: [
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, 'css-loader'],
},
],
},
plugins: [
new HtmlWebpackPlugin({
title: 'compare hash',
}),
],
optimization: {
splitChunks: {
chunks: 'all',
},
minimizer: [
new TerserPlugin({
extractComments: false,
}),
new MiniCssExtractPlugin({
filename: '[name].[fullhash].css',
}),
],
},
};
index.js
index.js 文件内容如下,其引用了 add.js、sub.js 和 index.css,以及第三方库 lodash。
import _ from 'lodash';
import { add } from './add';
import { sub } from './sub';
import './index.css';
const addResult = add(56 + 211);
const subResult = sub(213 - 53);
console.log(_.join([addResult, subResult], '---'));
const box = document.createElement('div');
box.innerText = 'compare hash';
document.body.append(box);
add.js
add.js 中是一个简单的求和函数
export function add(a, b) {
return a + b;
}
sub.js
sub.js 中是一个简单的求差函数
export function sub(a, b) {
return a - b;
}
index.css
index.css 中对字体颜色做了设置
div {
color: coral;
}
打包结果
fullhash
顾名思义,fullhash是全量的hash,是整个项目级别的。只要项目中有任何一个的文件内容发生变动,打包后所有文件的hash值都会发生改变。
上面的 webpack.config.js 中,已经将 js 和 css 文件打包后名称中带了 fullhash 选项,我们先执行 npx webpack
命令,对项目执行一次打包,打包后的文件如下,可以看到,所有文件的文件名中的 hash 值都是一样的:
然后我们对 add.js 进行一点修改:
export function add(a, b) {
+ console.log(a);
return a + b;
}
再次执行 npx webpack
,可以看到,所有文件的 hash 值都发生了改变:
我们只改变了 add.js,受到影响的文件只有 add.js 文件本身和依赖它的文件 index.js,其他的文件我们显然是没必要更新 hash 的,那么如何规避这种情况呢,这就提到了下面的 chunkhash。
chunkhash
chunkhash根据不同的入口文件(entry)进行依赖文件解析、构建对应的chunk,生成对应的哈希值。当某个文件内容发生变动时,再次执行打包,只有该文件以及依赖该文件的文件的打包结果 hash 值会发生改变
我们将 webpack.config.js 中的 fullhash 修改为 chunkhash :
// ...
module.exports = {
output: {
path: path.resolve(__dirname, './dist'),
- filename: '[name].[fullhash].js',
+ filename: '[name].[chunkhash].js',
clean: true,
},
// ...
optimization: {
splitChunks: {
chunks: 'all',
},
minimizer: [
new MiniCssExtractPlugin({
- filename: '[name].[fullhash].css',
+ filename: '[name].[chunkhash].css',
}),
],
},
};
然后将 add.js 改回最初状态:
export function add(a, b) {
- console.log(a);
return a + b;
}
再次执行 npx webpack
命令,打包结果如下:
可以看到 index.js 和 index.css 打包的 hash 值是一样的,这是因为在 index.js 中引用了 index.css ,打包后他们属于一个模块。
我们再次修改 add.js :
export function add(a, b) {
+ console.log(a);
return a + b;
}
执行 npx webpack
打包, 结果如下:
可以看到虽然公共库 lodash 和 sub.js 文件的打包值这次没有改变,但是除了 add.js 和 index.js 的打包值发生了变动之外, index.css 的打包 hash 值也随之 index.js 的打包hash值发生了改变,这并不是我们期望的。
这就有了 contenthash 的用武之地。
contenthash
contenthash 是只有当文件自己的内容发生改变时,其打包的 hash 值才会发生变动。
我们修改 webpack.config.js 中 MiniCssExtractPlugin 插件对 css 文件的打包名称,将 chunkhash 修改为 contenthash:
// ...
module.exports = {
// ...
optimization: {
splitChunks: {
chunks: 'all',
},
minimizer: [
new MiniCssExtractPlugin({
- filename: '[name].[chunkhash].css',
+ filename: '[name].[contenthash].css',
}),
],
},
};
然后执行 npx webpack
重新打包一下,打包结果如下:
可以看到此次 index.js 和 index.css 的打包结果的 hash 不再相同。我们再次修改一下 add.js 的内容:
export function add(a, b) {
- console.log(a);
return a + b;
}
执行npx webpack
,打包结果如下:
此次发现改变的 hash 只有 add.js 和 index.js 的打包结果,是符合我们预期的。
最佳实践
在生产环境下,我们对 output 中打包的文件名一般采用 chunkhash,对于 css 等样式文件,采用 contenthash,这样可以使得各个模块最小范围的改变打包 hash 值。
一方面,可以最大程度地利用浏览器缓存机制,提升用户的体验;另一方面,合理利用 hash 也减少了 webpack 再次打包所要处理的文件数量,提升了打包速度。
关于 webpack 中 fullhash、chunkhash 和 contenthash 的理解就到这里了,希望大家有所收获,有所疏漏之处也欢迎大家评论提点。
转载自:https://juejin.cn/post/6971987696029794312