前言
缓存可以降低网络流量,使网站加载速度更快。然而,如果我们在部署新版本时不更改资源的文件名,浏览器可能会认为它没有被更新,就会使用它的缓存版本。由于缓存的存在,当你需要获取新的代码时,就会显得很棘手。
我们可以通过必要的配置,确保 webpack 编译生成的文件能够被客户端缓存,而在文件内容变化后,能够请求到新的文件。
方式
1. 输出文件的文件名
通过使用 output.filename 进行文件名替换,可以确保浏览器获取到修改后的文件。[hash] 替换可以用于在文件名中包含一个构建相关(的 hash,但是更好的方式是使用 [chunkhash] 替换,在文件名中包含一个 chunk 相关的哈希
const HtmlWebpackPlugin=require('html-webpack-plugin')
module.exports = {
entry: './src/main.js',
devtool: 'inline-source-map',
plugins:[
new HtmlWebpackPlugin({
title:'caching'
})
],
output:{
filename:'[name].[chunkhash].js',//更改
},
};
打包结果如下。这个时候输出时,资源名都会被动态修改,这样就不会因为缓存而取不到新的文件了。

如果我们不做修改,再次运行构建,我们以为文件名会保持不变。然而,如果我们真的运行,可能会发现文件名可能会变,也可能不会。这也是因为 webpack 在入口 chunk 中,包含了某些样板(boilerplate,webpack 运行时的引导代码),特别是 runtime 和 manifest。
2. 提取模板
基于上面的问题,我们需要将 webpack 的样板和 manifest 提取出来。官方文档写的是用CommonsChunkPlugin方式,但我这边报错了,所以选择使用optimization.splitChunks的方式提取

const HtmlWebpackPlugin=require('html-webpack-plugin')
module.exports = {
//...
//提取manifest
optimization:{
runtimeChunk:{
name:'manifest'
},
splitChunks: {
chunks:"async"
},
},
//...
};
打包后可见被提取出来了

optimization.splitChunks也可以将第三方库(library)提取到单独的 vendor chunk 文件中,因为它们很少像本地的源代码那样频繁修改。因此通过提取,利用客户端的长效缓存机制,可以通过命中缓存来消除请求,并减少向服务器获取资源,同时还能保证客户端代码和服务器端代码版本一致:
假设这里安装了第三方库router
const HtmlWebpackPlugin=require('html-webpack-plugin')
module.exports = {
entry: {
main:'./src/main.js',
vender:['router'] //如果要提取多个库,可以在数组里添加,这里指提取router
},
//...
optimization:{
//...
splitChunks: {
chunks:"async",
//设置
cacheGroups:{
vender:{
name:"vender",//指定chunk的名字
chunks:'initial',
}
}
},
},
//...
};
可以发现第三方库被成功提取出来了

3.模块标识符
这时候,当我们添加一个模块print.js,并引入main.js时
//print.js
export default function print(text) {
console.log(text)
}
//main.js
import{print}from'./print' //引入
function component(){
var el=document.createElement('div');
el.innerHTML="123"
console.log(print('222'))
return el
}
document.body.appendChild(component())
发现其中main bundle的hash会随着自身内容的新增而变化,而vender bundle我们并没有修改,然而hash也变化了:

HashedModuleIdsPlugin可以解决这个问题:
const webpack = require('webpack');
module.exports = {
//...
plugins:[
//...
new webpack.HashedModuleIdsPlugin()
],
//...
};
这个时候当我们移除依赖print.js会发现只有main.js发生变化:

存疑:官方文档说:
manifestbundle会因为当前包含一个新模块的引用而发生变化。然而这里的hash并没有发生变化,不知道是提取的问题还是什么问题。