PWA 的 App Shell 模式到底该怎么实现?
我最近在尝试把一个单页应用改成 PWA,看到很多资料提到 App Shell 架构,说是要先缓存静态 UI,再动态加载内容。但我照着文档写 service worker,发现页面要么白屏,要么刷新后样式丢了。
我试过在 install 事件里缓存 HTML、CSS 和 JS 文件,像这样:
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open('app-shell-v1').then(cache => {
return cache.addAll([
'/',
'/styles/main.css',
'/js/app.js'
]);
})
);
});
但打开离线页面时,/ 缓存的 HTML 好像没生效,控制台还报错说 fetch 失败。是不是 App Shell 的 HTML 不能直接缓存根路径?还是我漏了什么关键步骤?
/缓存没问题,但得确保这个路径返回的是真正的 HTML 文件,而不是重定向到/index.html之类的;第二,Service Worker 的fetch拦截逻辑完全没写,只缓存不读取当然白屏;第三,App Shell 的核心是「先用缓存渲染骨架,再用网络内容更新」,不是简单把文件塞进 cache 就完事。我给你贴一个能跑的最小可行方案,你对照着改:
先确认你的
index.html里注册了 Service Worker:然后
sw.js这样写(重点在fetch里用 cache-first 策略):注意几个细节:第一,
self.skipWaiting()和self.clients.claim()必须加,否则刷新后可能还是旧版本 SW;第二,别缓存 API 接口,只缓 UI 骨架;第三,HTML 页面里一定要有 JS 去动态加载数据,不然缓存下来的 HTML 就是空壳,用户看不到内容。我当年就是忘了在index.html里加异步 fetch,以为缓存了 HTML 就万事大吉,结果离线全是白板。最后提醒一句:Chrome 里 Service Worker 不缓存 304 响应,如果你用 devtools 的 Disable cache 勾选了,缓存根本不会生效,调试的时候记得关掉这个选项。