优先用[contenthash]:它按文件内容生成哈希,js、css、图片各自独立变化,实现细粒度缓存;[chunkhash]因同chunk内资源共用哈希仍不精准;[hash]则整次构建全局统一,任意文件改动即全量失效。

Webpack中配置文件hash名,核心是让每个资源文件名携带其内容唯一标识,这样内容不变时文件名不变,浏览器就能复用缓存;内容一改,文件名就变,自然触发新资源加载。关键不是加hash,而是选对hash类型并配全关联项。
优先用[contenthash]代替[chunkhash]和[hash]
三种hash的区别很实际:
- [hash]:整次编译的全局哈希,改任意一个文件,所有输出文件名都变——缓存完全失效
- [chunkhash]:按入口或代码分割块(chunk)计算,同一chunk内JS和CSS共用一个hash——但CSS改了,JS的hash也跟着变,仍不精准
- [contenthash]:真正按文件内容生成哈希,JS改只影响JS文件名,CSS改只影响CSS文件名,图片改只影响对应图片名——这才是细粒度缓存的基础
所以output中应统一使用[contenthash]:
output: {
filename: '[name].[contenthash].js',
chunkFilename: '[name].[contenthash].js',
assetModuleFilename: 'assets/[name].[contenthash][ext]'
}
必须配合runtimeChunk隔离运行时代码
老版本Webpack(如4.x)默认把模块关系清单(manifest)写进每个chunk里,导致哪怕只改一行业务代码,main.js和vendors.js的contenthash都会变——因为manifest变了。解决方法是抽离runtime:
optimization: {
runtimeChunk: 'single'
}
这会生成一个独立的runtime.[contenthash].js,之后业务代码和第三方库各自稳定,只要内容没动,它们的hash就永不变化。
启用splitChunks分离第三方代码
光有contenthash还不够,得让第三方库(如lodash、vue)和业务代码分属不同chunk,否则它们总被一起打包,一动全动:
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
vendor: {
test: /[\/]node_modules[\/]/,
name: 'vendors',
priority: 10
}
}
}
}
这样vendors.[contenthash].js只随node_modules内容变化,日常业务迭代不会牵连它。
服务端需配强缓存响应头
Webpack生成带contenthash的文件名只是第一步。真正让浏览器长期缓存,还得靠HTTP响应头:
- 静态资源(.js、.css、.png等)设
Cache-Control: public, max-age=31536000, immutable - HTML文件不能强缓存,应设
Cache-Control: no-cache或短时效,确保能及时加载新资源引用
验证是否生效:打开浏览器开发者工具→Network→点某个JS/CSS文件→看Response Headers里是否有上述Cache-Control字段。











