PWA 的 App Shell 缓存不生效是怎么回事?
我按照教程用 Workbox 实现了 App Shell 模式,但离线时页面还是白屏,缓存好像没起作用。
我在 sw.js 里注册了路由和缓存策略,关键代码如下:
workbox.routing.registerRoute(
({ request }) => request.mode === 'navigate',
new workbox.strategies.NetworkFirst({
cacheName: 'app-shell',
plugins: [
new workbox.cacheableResponse.CacheableResponsePlugin({
statuses: [200],
}),
],
})
);
也确认了 service worker 安装成功,但刷新后离线访问还是加载失败。是不是 App Shell 的 HTML 没被正确缓存?
index.html加进workbox.precaching.precacheAndRoute,或者改成用StaleWhileRevalidate策略并配合cacheName显式缓存 HTML,比如:先确认两点:
1. 你的 index.html 本身能不能离线打开?打开浏览器开发者工具的 Application → Service Workers,看有没有命中缓存的记录;
2. 打开 Application → Cache Storage → app-shell,看看里面是不是只有 index.html,没有其他静态资源?
如果只有 HTML,那你要加一条规则,把静态资源也缓存了,比如 JS CSS 文件:
workbox.routing.registerRoute(
({ request }) => request.destination === 'style' || request.destination === 'script',
new workbox.strategies.StaleWhileRevalidate({
cacheName: 'static-resources',
})
);
或者更稳妥点,直接用 Workbox 的默认策略模板,比如:
workbox.precaching.precacheAndRoute(self.__WB_MANIFEST);
这个 manifest 是构建时生成的,包含所有静态资源。如果你没用构建工具(比如 webpack + workbox 插件),那得自己列个清单,或者至少把 JS CSS 图片都加个路由缓存。
另外检查一下 service worker 是否真的控制了页面——在 sw.js 里加一句:
self.addEventListener('install', event => {
console.log('SW installed');
});
在页面里加:
if ('serviceWorker' in navigator) {
navigator.serviceWorker.ready.then(() => console.log('SW ready'));
}
看看控制台有没有输出。有时候 sw.js 没生效是因为路径不对,比如你把 sw.js 放在 /sw.js,但页面在 /app/,那 scope 就是 /,但页面可能加载不了。
复制过去试试这个完整版:
if (workbox) {
workbox.precaching.precacheAndRoute(self.__WB_MANIFEST || []);
workbox.routing.registerRoute(
({ request }) => request.mode === 'navigate',
new workbox.strategies.NetworkFirst({
cacheName: 'app-shell',
plugins: [
new workbox.cacheableResponse.CacheableResponsePlugin({
statuses: [200],
}),
],
})
);
workbox.routing.registerRoute(
({ request }) => request.destination === 'style' || request.destination === 'script',
new workbox.strategies.StaleWhileRevalidate({
cacheName: 'static-resources',
})
);
}
记得用 npm run build 生成 manifest 后再部署,别直接传个 sw.js 就完事。