全站SVG图标离线可用的关键在于精准缓存策略:预缓存核心导航、框架级Sprite及静态路径SVG;URL匹配需忽略查询参数并覆盖document/image请求;fetch必须首行respondWith;更新时同步升级CACHE_NAME并在activate中清理旧缓存。
要让全站 svg 图标真正离线可用、秒级加载,关键不在“缓存多少”,而在于“缓存谁、怎么匹配、怎么交付”。service worker 不是万能胶水,它需要精准的资源识别、一致的 url 管理和无延迟的响应链路。
明确哪些 SVG 图标必须进预缓存
不是所有 SVG 都适合 install 阶段预存。优先缓存以下三类:
- 核心导航图标:如 logo.svg、menu.svg、close.svg、search.svg —— 页面首次渲染即需,缺一不可
- 框架级图标资源:若使用 Lucide、Feather 或自建 SVG Sprite 文件(如 icons-sprite.svg),必须整文件预缓存
- 静态路径图标:存放在 /icons/ 目录下、路径固定且无版本参数的 SVG(例如 /icons/home.svg),避免运行时动态拼接导致匹配失败
跳过带查询参数(?v=1.2.3)、哈希后缀(home-abc123.svg)或由 JS 动态生成路径的图标——它们更适合 runtime caching + ignoreSearch 匹配。
URL 匹配必须零误差,否则缓存形同虚设
caches.match() 默认严格比对完整 URL,包括协议、域名、路径、查询参数和大小写。常见失效原因:
- 页面请求
/icons/user.svg?v=2,但缓存的是/icons/user.svg - 缓存了
/Icons/user.svg(大写 I),而 HTML 中引用的是/icons/user.svg - SVG Sprite 被内联到 HTML 中,但 fetch 事件没拦截 document 类型请求(
event.request.destination === 'document')
解决办法:
- 构建时统一图标路径规范,禁用自动加版本参数;或在
cache.addAll()列表中显式带上相同参数 - 运行时匹配用
caches.match(request, { ignoreSearch: true }) - 在 fetch 事件中加判断:
if (request.destination === 'image' || request.destination === 'document'),确保 SVG 和含 SVG 的 HTML 都被覆盖
fetch 响应必须第一时间接管,不能留空档
浏览器对 fetch 事件的响应有超时机制。如果 event.respondWith() 调用太晚,或只在部分分支里调用,未命中的请求会退回到网络,失去离线能力。
正确写法是:所有 fetch 监听器第一行就写 event.respondWith(...),内部再做逻辑分发:
self.addEventListener('fetch', event => {
event.respondWith(
(async () => {
const req = event.request;
// 仅对 SVG 图标和 HTML 页面启用缓存优先
if (req.destination === 'image' && req.url.endsWith('.svg') ||
req.destination === 'document') {
const cached = await caches.match(req, { ignoreSearch: true });
if (cached) return cached;
}
// 兜底走网络,但记得 clone Response 再缓存(如需)
return fetch(req);
})()
);
});缓存更新要干净,避免旧版本残留干扰
每次修改图标或更新缓存策略,必须同步升级 CACHE_NAME(如从 v1 → v2),并在 activate 阶段彻底删除旧缓存:
- 不要只靠
self.skipWaiting()强制激活,它不清理旧缓存 - activate 事件中必须遍历
caches.keys(),逐个caches.delete()旧名缓存 - 搭配
self.clients.claim()确保当前页立即受新 SW 控制
否则用户可能长期卡在旧图标版本,甚至因缓存键冲突导致部分图标无法加载。











