React PWA离线模式无法运行问题及sw-toolbox集成咨询
解决React PWA离线加载问题及sw-toolbox集成方法
一、先修复现有Service Worker的问题
你的Service Worker存在几个关键错误,直接导致离线加载失败:
cache.addAll()参数使用错误cache.addAll()仅接受单个资源数组作为参数,你传入多个数组的写法无效,只有第一个urlsToCache会被缓存,其余资源都未加入缓存池。无效的资源路径
像/shirt-trouser/shirts/.jpeg这类路径缺少具体文件名,无法匹配实际图片资源,缓存这类路径没有意义,必须替换为真实的图片文件路径(比如/shirt-trouser/shirts/blue-shirt.jpeg)。缺少fetch事件拦截逻辑
Service Worker安装完成后,必须监听fetch事件来拦截网络请求,从缓存返回资源;否则离线时浏览器仍会发起网络请求,最终因无网络导致失败。
修正后的基础Service Worker代码
let CACHE_NAME = 'my-site-cache-v1'; // 合并所有需要预缓存的资源为一个数组 const urlsToCache = [ '/', '/index.html', // 替换为实际存在的图片路径,示例: // '/shirt-trouser/shirts/shirt1.jpeg', // '/shirt-trouser/shirts/shirt2.jpg', '/config.js', '/index.js', '/App.js', '/components/BabylonAvatar.js', '/components/SceneComponent.js', '/avatar/newformalwalk13.glb' ]; // 安装阶段:预缓存资源 self.addEventListener('install', function(event) { event.waitUntil( caches.open(CACHE_NAME) .then(function(cache) { console.log('Opened cache'); return cache.addAll(urlsToCache); }) // 跳过等待,立即激活新的Service Worker .then(() => self.skipWaiting()) ); }); // 激活阶段:清理旧缓存 self.addEventListener('activate', function(event) { event.waitUntil( caches.keys().then(function(cacheNames) { return Promise.all( cacheNames.filter(function(cacheName) { return cacheName !== CACHE_NAME; }).map(function(cacheName) { return caches.delete(cacheName); }) ); }) ); }); // 拦截fetch请求,优先从缓存返回资源 self.addEventListener('fetch', function(event) { event.respondWith( caches.match(event.request) .then(function(response) { // 缓存有资源则直接返回,否则发起网络请求 if (response) { return response; } return fetch(event.request); }) ); });
二、sw-toolbox与React的集成方法
sw-toolbox可以简化Service Worker的缓存策略管理,具体步骤如下:
1. 安装sw-toolbox
在React项目中执行安装命令:
npm install sw-toolbox --save
2. 创建Service Worker文件(如sw.js)
引入sw-toolbox并配置不同资源的缓存策略:
importScripts('node_modules/sw-toolbox/sw-toolbox.js'); // 设置缓存名称前缀 toolbox.options.cache.name = 'my-react-pwa-cache'; // 页面资源:缓存优先,同时后台更新缓存 toolbox.router.get('/', toolbox.cacheFirst); toolbox.router.get('/index.html', toolbox.cacheFirst); // JS/CSS资源:网络优先,网络失败则用缓存 toolbox.router.get('/*.js', toolbox.networkFirst); toolbox.router.get('/*.css', toolbox.networkFirst); // 图片资源:缓存优先,设置缓存上限和有效期 toolbox.router.get('/shirt-trouser/*/*.{jpeg,jpg,png}', toolbox.cacheFirst, { cache: { maxEntries: 50, // 最多缓存50个图片资源 maxAgeSeconds: 30 * 24 * 60 * 60 // 缓存有效期30天 } }); // 3D模型资源:缓存优先 toolbox.router.get('/avatar/*.glb', toolbox.cacheFirst); // 激活时接管所有客户端 self.addEventListener('activate', () => { self.clients.claim(); });
3. 在React项目中注册Service Worker
在React入口文件(如index.js)中添加注册逻辑:
if ('serviceWorker' in navigator) { window.addEventListener('load', () => { navigator.serviceWorker.register('/sw.js') .then(registration => { console.log('Service Worker registered: ', registration); }) .catch(error => { console.log('Service Worker registration failed: ', error); }); }); }
4. 配置打包工具(以Create React App为例)
将sw.js放在项目的public目录下,确保构建时会被复制到build目录;若使用自定义Webpack配置,可通过copy-webpack-plugin将sw.js和node_modules/sw-toolbox/sw-toolbox.js复制到构建输出目录。
三、离线功能测试注意事项
- 确保所有需离线访问的资源路径正确,避免遗漏或错误路径。
- 使用Chrome DevTools的
Application > Service Workers勾选Offline选项,模拟离线环境测试。 - 修改Service Worker后,需更新
CACHE_NAME(如改为my-site-cache-v2),触发新的安装和激活流程,替换旧缓存。
内容的提问来源于stack exchange,提问作者Asha Datla
相关产品推荐
相关产品推荐

