要实现带“版本镜像”功能的离线持久化策略,核心是将Service Worker作为可控缓存代理层,按语义化版本(如v1.2.3)隔离缓存、预载资源、静默更新,全程纯前端可控。

要实现带“版本镜像”功能的离线持久化策略,核心是把 Service Worker 当作一个可控的缓存代理层,按语义化版本(如 v1.2.3)组织缓存空间,并确保每次版本变更时旧缓存自动清理、新资源精准预载、线上更新可后台静默完成。整个过程不依赖后端接口,纯前端可控。
版本命名与缓存隔离
每个应用版本对应唯一缓存名称,避免跨版本污染。例如:
- 缓存名格式建议为
`${APP_NAME}-v${VERSION}`,如"gh-mirrors-de-v1.5.0" - 在
install事件中打开该缓存,只添加当前版本明确声明的资源列表 - 禁止复用旧缓存名,哪怕仅 patch 号变化(如
v1.5.0 → v1.5.1)也应启用新缓存名,保证强一致性
预缓存 + 版本清单校验
构建阶段生成一份静态 manifest.json,包含该版本所有需离线可用的资源路径及哈希值。Service Worker 加载时做两件事:
- 读取
manifest.json,调用caches.open(cacheName).addAll()预缓存全部条目 - 对关键 HTML 文件(如
/index.html)额外执行哈希比对:若缓存中 HTML 内容哈希与清单不符,拒绝使用该缓存,强制走网络回退(防止 HTML 被意外覆盖但缓存未更新)
fetch 拦截中的版本路由逻辑
在 fetch 事件中,根据请求目标和当前激活的缓存版本,动态决定响应来源:
- 对
document类型请求(页面导航),始终优先匹配当前激活缓存中的 HTML;若缺失或校验失败,则发起网络请求,并在响应成功后克隆写入当前版本缓存 - 对
script/style/image等静态资源,只查当前版本缓存;不命中则报 404,不降级到旧版本缓存(避免混用导致 JS/CSS 不兼容) - 对 API 接口类请求(
destination === 'empty'且 URL 匹配/api/),默认走网络,失败时可 fallback 到 IndexedDB 中按版本存储的模拟响应(需业务层配合)
版本切换与平滑过渡
当新版 Service Worker 安装完成,需协调页面更新行为:
- 在
waiting状态时,通过navigator.serviceWorker.addEventListener('controllerchange')监听激活完成 - 向用户提示“新版本已就绪,刷新页面立即生效”,或自动触发
window.location.reload(true) - 在
activate事件中,遍历caches.keys(),删除所有不含当前版本号的缓存(如gh-mirrors-de-v1.4.*),释放空间

















