应使用[contenthash]而非[hash]:前者按文件内容生成哈希,改一行css仅更新对应文件名,避免全量缓存失效;后者是全局构建哈希,任意文件变更都会导致所有输出文件名改变。

Webpack 里 contenthash 和 hash 到底该用哪个
用 [contenthash],别用 [hash]——前者按文件内容生成哈希,后者是整个构建产物的哈希。改一行 CSS,[hash] 会让所有 JS/CSS 文件名全变,缓存全部失效。
常见错误现象:output.filename: 'js/[name].[hash].js' 导致每次构建后浏览器重新下载全部 JS,哪怕只改了注释。
-
[contenthash]必须配合HtmlWebpackPlugin才能生效,它会读取真实输出文件名并注入 HTML - CSS 提取(如
MiniCssExtractPlugin)也要显式配置filename: '[name].[contenthash].css',否则默认不带 hash - 动态
import()的 chunk 同样需要[contenthash],否则懒加载模块名不变,浏览器可能复用旧缓存
Vite 构建时怎么让 JS/CSS 文件带内容哈希
Vite 3.0+ 不支持 [contenthash],但底层仍是内容哈希;你得用 [hash],它实际是截取内容哈希的前 8 位(比如 [hash:8]),语义等价。
关键不是写对变量名,而是必须覆盖三类输出模板,否则部分文件没哈希:
-
entryFileNames: 'assets/[name].[hash:8].js'(入口 JS) -
chunkFileNames: 'assets/[name].[hash:8].js'(异步 chunk) -
assetFileNames: 'assets/[name].[hash:8].[ext]'(图片、字体等)
漏配其中任意一项,对应资源就会变成 main.js 这种无哈希名,导致缓存穿透。
HTML 中的 src 和 href 怎么自动替换成带哈希的路径
不能手写 <script src="main.ea7f2d.js"></script>,这是反模式:构建后哈希一变,HTML 就 404;本地开发又得切回无 hash 路径,徒增条件判断。
正确做法取决于构建工具:
- Webpack:靠
HtmlWebpackPlugin自动扫描template中的<script></script>、<link>,再根据compilation.assets替换为真实带哈希的文件名 - Vite:对
import或new URL('./logo.png', import.meta.url)这类写法自动重写;但传统<img src="logo.png">不会处理,必须把这类资源放进src/assets/目录下 - 如果用了
public/目录里的资源(如public/favicon.ico),它不会被哈希,得手动改名或走 CDN 版本号策略
为什么 html-bundler-webpack-plugin 比 html-loader + url-loader 更可靠
老方案中,html-loader 只解析 HTML 结构,不主动扫描 <img src="./xxx.png"> 这类属性值,也不触发 Webpack 的资源规则匹配,结果就是图片 404。
html-bundler-webpack-plugin 是专为 HTML 模板设计的,它能深度扫描所有资源引用(src、href、poster、icon 等),自动匹配 Webpack 规则,并把原始路径替换成最终带哈希的产物路径。
容易踩的坑:
- 仍保留
html-loader规则(如/\.html$/)会和插件冲突,报错“multiple modules match” - 插件默认不处理
public/下的资源,那些路径得提前挪进src/或显式配置publicPath - 若 HTML 中有内联 SVG 或 base64 图片,插件默认跳过,需额外配置
loader: 'raw'或inline: true
哈希命名的核心不是“加一串随机字符”,而是让文件名与内容强绑定;路径替换的关键也不是“字符串替换”,而是构建阶段打通 HTML 模板与资源产出的映射关系。漏掉任一环,缓存就形同虚设。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











