知人者智,自知者明,胜人者有力,自胜者强。——老子
简介
在webpack
中有三种hash
可以配置,分别是hash
、chunkhash
、contenthash
他们是不对的可以针对不同的配置,首相要搞清楚这三种的hash
的区别,什么场景下,适合用哪种。
hash 所有文件哈希值相同,只要改变内容跟之前的不一致,所有哈希值都改变,没有做到缓存意义
chunkhash
当有多个chunk
,形成多个bundle
时,如果只有一个chunk
和一个bundle
内容变了,其他的bundle
的hash
都会发生变化,因为大家都是公用的一个hash
,这个时候chunkhash
的作用就出来了。它根据不同的入口文件(Entry)
进行依赖文件解析、构建对应的 chunk
,生成对应的哈希值。
contenthash
在打包的时候我们会在js
中导入css
文件,因为他们是同一个入口文件,如果我只改了js
得代码,但是他的css
抽取生成css
文件时候hash
也会跟着变换。这个时候contenthash
的作用就出来了。
下面直接用代码验证上面的猜想。
一个简单的webpack配置
我们现在就只创建一个能编译js
的webpack
配置,步骤如下:
- 创建一个空文件加,并且在当文件夹中打开
bash or cmd
。 npm init -y
生成package.json
。- 如果你安装了
cnpm or yarn
就执行cnpm i webpack webpack-cli -D
, 安装webpack
的包。 - 创建
src
,在src
内部创建chunk0.js
、chunk1.js
、common.js
、index.js
、style.css
,并且编写内部代码 - 在项目根目录创建
webpack.config.js
- 直接在
cmd
中运行webpack
文件目录如下:
下面是代码 chunk0.js
export default function add (a, b) {
return a + b;
};
chunk1.js
export default function flow () {
return 'flow';
};
common.js
export default function commonJs () {
return 'commonJs';
};
index.js
import add from './chunk0.js';
import commonJs from './common';
console.log(add(1, 2));
console.log(commonJs());
style.css
body {
background: #000;
}
webpack.config.js
module.exports = {
mode: "production", // 如果不添加就会警告
entry: {
index: "./src/index.js", // 一个入口文件
chunk1: "./src/chunk1.js" // 两一个入口文件
},
output: {
filename: "[name].[hash].js" // 出口文件
}
}
hash
我们直接运行webpack
,运行结果如下图所示:
只有一个hash,所有文件的hash都是相同:
如果我们改变修改chunk1.js中的代码:
export default function flow () {
return 'flow1'; // flow => folw1
};
再运行webpack发现所有的hash都变化了,如下图所示:
对比发现他们的hash并不相同了,这个时候如果想修改了chunk1.js,index.js不产生变化,就要用到chunkhash。
chunkhash
- 第一步 我们先把webpack.config.js做一下修改
module.exports = {
mode: "production",
entry: {
index: "./src/index.js",
chunk1: "./src/chunk1.js"
},
output: {
filename: "[name].[chunkhash].js" // hash => chunkhash
}
}
- 第二步 我们运行
webpack
chunk
的hash
并不相同了。
- 第三部 我们修改
chunk1.js
export default function flow () {
return 'flow11111'; // flow1 => flow11111
};
- 再运行
webpack
根据图片我们看到了chunk1.js
的hash
变化,而index.js
的hash
并没有变化,达到了我们预期的效果,对我们线上的缓存也是比较好的。
contenthash
但是当我们一个js
文件里面引用了一个css
文件,如果我么修改了css
文件内的内容,我们css
中的内容,会发发现这整个bundle
的hash
也会发生更新。
我们要引入css
,并且要把css
提出、压缩生成一个css
文件,就要借助一个webpack
的插件,叫做MiniCssExtractPlugin
,他可以帮我提取css到css文件,并且压缩css。
- 第一步先安装
css-loader
、mini-css-extract-plugin
包
cnpm install css-loader mini-css-extract-plugin -D
- 第二步修改
webpack.config.js
如下
const MiniCssExtractPlugin = require("mini-css-extract-plugin"); // 新增
module.exports = {
mode: "production",
entry: {
index: "./src/index.js",
chunk1: "./src/chunk1.js"
},
output: {
filename: "[name].[chunkhash].js"
},
module: { // 新增
rules: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader"
]
}
]
},
plugins: [ // 新增
// 提取css插件
new MiniCssExtractPlugin({
// Options similar to the same options in webpackOptions.output
// both options are optional
filename: "[name].[chunkhash].css"
})
]
};
- 第三步运行webpack
看代码可以看到index.css
和index.js
的hash
是一样的。
- 第四步修改style.css
html {
font-size: 13px;
}
- 第五步运行webpack
对比两次构建的hash
,发现只修改了style.css
的文件,引入他的index.js
确也更新了hash
,这个时候就需要contenthash
来发挥作用了。
- 第六步修改
webpack.config.js
并且运行 webpack
const MiniCssExtractPlugin = require("mini-css-extract-plugin"); // 新增
module.exports = {
mode: "production",
entry: {
index: "./src/index.js",
chunk1: "./src/chunk1.js"
},
output: {
filename: "[name].[chunkhash].js"
},
module: { // 新增
rules: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader"
]
}
]
},
plugins: [ // 新增
// 提取css插件
new MiniCssExtractPlugin({
// Options similar to the same options in webpackOptions.output
// both options are optional
filename: "[name].[contenthash].css"
})
]
};
看到他们直接hash就是不同的。
- 修改
common.js
,直接运行webpack
export default function commonJs () {
return 'commonJs1';
};
看到修改js时我们的css文件的hash并没有变更。
注意,当使用
contenthash
时,如果修改js文件,css文件的hash不会变化,但是修改js的文件,css文件的hash也会变化。
总结
hash 所有文件哈希值相同; chunkhash 根据不同的入口文件(Entry)进行依赖文件解析、构建对应的 chunk,生成对应的哈希值; contenthash 计算与文件内容本身相关,主要用在css抽取css文件时。