部署后React PWA无法缓存文件问题及解决方案咨询
解决Netlify部署后React PWA缓存失败问题
针对你遇到的缓存失败报错,需要对sw.js做以下几处关键修改:
1. 修正缓存资源列表
- 移除
./App.js:React打包后源码文件不会暴露在部署根目录,该请求会返回404,直接导致cache.addAll执行失败。 - 移除硬编码哈希的JS/CSS文件:Netlify部署后的静态资源哈希值会和本地构建的不一致,硬编码会导致请求不存在的文件。改为缓存核心入口文件和通用静态资源,动态资源在fetch阶段处理。
修改后的缓存列表:
var urlCache = [ "/manifest.json", "/logo192.png", "/", "/index.html" ];
2. 移除硬编码的localhost地址
部署后localhost地址无效,全部改为相对路径匹配:
- 将通知触发条件从判断
http://localhost:3000/static/js/main.chunk.js改为匹配相对路径特征 - 通知图标地址改为
/logo192.png
3. 修复离线缓存的fetch逻辑
原逻辑仅在离线时处理请求,且未处理缓存未命中的情况,改为优先从缓存读取,缓存无则请求网络并更新缓存的策略,同时兼容单页应用路由:
this.addEventListener("fetch", (event) => { // 所有请求都走缓存优先策略 event.respondWith( caches.match(event.request) .then(cachedResponse => { // 如果缓存有数据,直接返回 if (cachedResponse) { return cachedResponse; } // 缓存无数据则请求网络,同时将新资源存入缓存 return fetch(event.request) .then(networkResponse => { caches.open(CACHE_NAME) .then(cache => { cache.put(event.request, networkResponse.clone()); }); return networkResponse; }) // 离线且缓存无匹配时,返回index.html处理单页路由 .catch(() => caches.match("/index.html")); }) ); // 离线时显示通知(匹配任意静态JS请求即可) if (!navigator.onLine && event.request.url.includes("/static/js/")) { event.waitUntil( this.registration.showNotification("离线模式", { body: "当前已切换至离线缓存", icon: "/logo192.png" }) ); } });
4. 修正activate事件的缓存清理逻辑
原逻辑会删除所有缓存,改为仅删除旧版本缓存,保留当前有效缓存:
this.addEventListener("activate", function (event) { event.waitUntil( caches.keys().then(function (cacheNames) { return Promise.all( cacheNames .filter(function (name) { // 只删除不是当前缓存名称的旧缓存 return name !== CACHE_NAME; }) .map(function (name) { return caches.delete(name); }) ); }) ); });
修改后的完整sw.js代码
let CACHE_NAME = "codePwa-v1"; // 加版本号方便后续更新缓存 var urlCache = [ "/manifest.json", "/logo192.png", "/", "/index.html" ]; // 安装Service Worker并缓存核心资源 this.addEventListener("install", (event) => { event.waitUntil( caches.open(CACHE_NAME).then((cache) => { return cache.addAll(urlCache); }) ); // 强制激活新的Service Worker this.skipWaiting(); }); // 处理资源请求,缓存优先策略 this.addEventListener("fetch", (event) => { event.respondWith( caches.match(event.request) .then(cachedResponse => { if (cachedResponse) { return cachedResponse; } return fetch(event.request) .then(networkResponse => { caches.open(CACHE_NAME) .then(cache => { cache.put(event.request, networkResponse.clone()); }); return networkResponse; }) .catch(() => caches.match("/index.html")); }) ); if (!navigator.onLine && event.request.url.includes("/static/js/")) { event.waitUntil( this.registration.showNotification("离线模式", { body: "当前已切换至离线缓存", icon: "/logo192.png" }) ); } }); // 激活时清理旧缓存 this.addEventListener("activate", function (event) { event.waitUntil( caches.keys().then(function (cacheNames) { return Promise.all( cacheNames .filter(function (name) { return name !== CACHE_NAME; }) .map(function (name) { return caches.delete(name); }) ); }) ); // 立即控制所有打开的页面 this.clients.claim(); });
额外注意:部署到Netlify时,确保public/sw.js被正确部署,且React应用的manifest.json配置正确,同时在index.html中注册Service Worker:
// 在index.html的script标签中添加 if ('serviceWorker' in navigator) { window.addEventListener('load', () => { navigator.serviceWorker.register('/sw.js') .then(registration => { console.log('SW registered: ', registration); }) .catch(registrationError => { console.log('SW registration failed: ', registrationError); }); }); }
内容的提问来源于stack exchange,提问作者Abhishek Negi
相关产品推荐
相关产品推荐

