前端多版本发布零 404 部署实践
在频繁迭代的前端项目中,发布新版本后用户遭遇 404 是个常见痛点。本文不讲虚的,直接拆解现象、根因,并给出我们落地的一套工程化方案。
1. 现象:为什么发布新版本后会出现 404?
想象一个真实场景:
- 10:00 用户打开了你的网页(加载的是 v1.0.4 的 HTML)
- 10:10 你发布了 v1.0.5
- 用户没有刷新页面,继续点击某个功能
- 页面尝试按旧 HTML 里的地址加载某个 chunk:
/assets/pages-about-about.DK5VADjQ.js - 服务器上只剩 v1.0.5 的文件,旧的被删了 → 直接 404
关键点在于:HTML 决定了要加载哪些 JS/CSS(包含具体 hash 文件名)。只要用户手上是旧 HTML,就会请求旧版 hash 的文件。如果服务器把旧文件删了,用户自然就会 404。
2. 根因:不是缓存,而是'源站有没有旧文件'
很多文章只讲'内容哈希 + immutable 缓存',默认隐含'旧文件在源站/存储里还存在'。
- 有缓存:命中本地/中间缓存,自然不 404
- 没缓存:会去源站拉,如果源站还保留旧文件,也不会 404
- 真正的 404 出在'把旧资源从源站删了',而不是'浏览器没缓存'
结论很明确:避免 404 的关键不是浏览器缓存,而是'源站/存储上保留旧文件一段时间'。
3. 方案总览(从易到难)
- A. 接受小概率 404 → 弹窗提示'有新版本,请刷新'。简单,但体验打断,不优雅。
- B. Service Worker 强制刷新 → 简化实现;用户会被强制 reload,可能丢失上下文。
- C. 不删旧资源(推荐) → 源站/存储保留最近 N 个版本的资源;HTML 短缓存。旧 HTML 始终能拿到对应 js/css,零 404,体验最佳。
- D. 网关/Node 层按 manifest 做 chunk 兜底 → 复杂度高;适合更重的后端网关治理。
本文主讲 C 方案。
4. 我们的落地:/assets 聚合 + /versions 备份 + HTML 短缓存
目标很简单:
- 页面永远从
/assets加载资源(统一入口,不改路径) - 保留最近 3~5 个版本的所有资源在
/assets,旧 HTML 永远能命中 - 每次发布只切换入口 HTML(
dist/current),不动/assets
目录结构建议如下:
dist/
├── current/ # 当前入口(index.html、manifest.json 等)
├── assets/ # 资源聚合池(最近 N 个版本的 js/css/png/…)
└── versions/ # 版本档案(每次发布的完整备份)
├── v1.0.5/
│ ├── index.html
│ └── assets/*
├── v1.0.4/
└── ...
发布流程(关键规则):
- 先 build(产物在
dist/build/h5) - deploy:将
dist/build/h5复制到dist/current(并写入manifest.json) - 同步最近 N 个版本的
assets/*到dist/assets(追加,不覆盖已存在同名 hash 文件) - 清理
dist/assets中'超出 N 版本范围'的多余文件(可控)

