前言
我们知道,为了优化体验,浏览器在加载资源时,有缓存机制。当浏览器判断待加载资源没有更新时,就从缓存中获取文件资源。
一般通用的方法是将资源设置为强制缓存,并给资源名称添加后缀值。当资源有更新时,修改其后缀值,重新获取HTML页面时,就可以实现资源的更新。
在webpack中,我们可以通过配置来实现自动给资源文件添加后缀值,即文件指纹。
配置文件指纹
我们在webpack中,通过output的filenames属性,可以设置输出文件的名称。比如我们配置如下:
// index.js
console.log('hello world!');
// main.js
console.log('hello webpack!');
// webpack.prod.config.js
entry: {
index: './src/index.js',
main: './src/main.js',
},
output: {
filename: '[name].js', // [name]是表示模块名称,对应entry的模块
path: path.resolve(__dirname, 'dist')
}
则构建出来的文件如下所示:
hash
那么,我们怎么给文件添加文件指纹呢?这里我们需要使用[hash],来重新设置下filenames属性:
entry: {
index: './src/index.js',
main: './src/main.js',
},
output: {
filename: '[name].[hash].js',
path: path.resolve(__dirname, 'dist')
}
再次打包构建后,可以看到生成的文件已经自动添加了hash值。
但是,生成的这两个bundle文件,都有相同的hash值。这是个什么原因呢?在官网中,我们可以看见对[hash]的描述:
模块标识符(module identifier)的 hash
那么,什么是模块标识符?我们知道,webpack是一个打包编译的过程,这个标识符,标识的就是这个打包的过程。所以,在这个打包编译过程中生成的bundle文件,都具有统一的hash值。
并且,如果我们修改其中一个js文件,再次打包的话,则会将两个bundle文件的hash值一起修改,那么我们缓存的目的将失效。
chunkhash
我们了解了[hash]无法解决我们缓存的目目的,那么我们应该怎样解决这个问题?这里就需要[chunkhash]登场了。
我们先看下[chunkhash]的官方描述:
chunk 内容的 hash
在webpack中,chunk指代的是模块,所以,chunkhash就是模块的hash,会按照每个模块内容计算hash。
我们重新配置下filenames属性:
entry: {
index: './src/index.js',
main: './src/main.js',
},
output: {
filename: '[name].[chunkhash].js',
path: path.resolve(__dirname, 'dist')
}
再次打包构建后,我们可以看见重新构建完成的bundle文件的hash值是不一样的。
contenthash
上面我们通过配置[chunkhash],来达到我们对js文件资源的缓存意义。
但是,在项目中不仅仅只有js文件,还有css文件和图片等静态资源。现在我们将入口文件index.js及其对应的依赖文件index.css打包在同一个模块,使用相同的chunkhash。若对应css改变,则构建出来的bundle文件的的chunkhash也会随之改变,但入口文件xx.js的内容并没有改变,所以没有完全达到缓存意义。
这里,我们首先需要将css从bundle文件抽离出来,这里我们使用插件mini-css-extract-plugin来达到我们的目的。
// webpack.prod.config.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
module: {
rules: [
{
test: /.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader'
],
}
],
},
plugins: [
new MiniCssExtractPlugin(),
],
}
这时,我们可以看见css已经单独抽离:
接下来,我们需要给css文件添加hash值。这里我们需要了解下[contenthash],[contenthash]表示根据文件内容生成hash值,内容不同hash值不同。
// webpack.prod.config.js
plugins: [
new MiniCssExtractPlugin({
filename: '[name].[contenthash].css',
}),
],
注:我们需要在MiniCssExtratPlugin中设置filename
再次打包,就可以看见生成的css的hash值和js的hash值不同。
这样设置之后,我们单独修改css的话,也只会重新生成css的hash值,而不会修改js的hash。
图片的hash
我们在webpack中,通过file-loader或url-loader来处理图片,这时设置图片的hash,需要注意的是[hash]表示的是根据文件内容生成hash。
官网说明可以点击这里。
总结
通过webpack设置文件指纹,达到缓存目的的一般方法:
- js: 配置
output的filenames属性,文件指纹设置为[chunkhash] - css: 使用MiniCssExtratPlugin抽离文件,文件指纹设置为
[contenthash] - 图片: 使用
file-loader或url-loader,文件指纹设置为[hash]