Vite+React SPA配置Workbox实现PWA离线自定义fallback页面失败求助
解决Vite-PWA离线时无法返回自定义offline.html的问题
问题根源
你遇到的核心问题是预缓存的index.html优先级高于Workbox的路由规则:默认情况下Vite-PWA会将SPA入口index.html加入预缓存列表,当离线时,所有导航类请求(request.mode === 'navigate')会直接命中预缓存的index.html,而非触发你配置的离线回退逻辑。
解决方案
以下提供两种可行的配置方案,根据你的使用场景选择即可:
方案一:使用generateSW模式(自动生成SW)
修改vite.config.ts中的PWA配置,重点是排除index.html的预缓存,让导航请求走自定义路由策略:
import { VitePWA } from 'vite-plugin-pwa'; export default { plugins: [ VitePWA({ workbox: { globPatterns: ['**/*.{png,svg,ico,txt,js,html,css}'], navigationPreload: true, // 确保offline.html被加入预缓存 additionalManifestEntries: [ { url: '/offline.html', revision: '1' } ], // 排除index.html的预缓存,强制导航请求走runtimeCaching exclude: ['index.html'], runtimeCaching: [ { urlPattern: ({ request }) => request.mode === 'navigate', handler: 'NetworkFirst', options: { cacheName: 'navigation-cache', networkTimeoutSeconds: 1, // 快速判断网络是否不可用 plugins: [ { handlerDidError: async () => { // 网络失败时返回预缓存的offline.html return caches.match('/offline.html'); } } ] } } ] } }) ] };
方案二:使用injectManifest模式(自定义SW)
如果需要更灵活的SW控制,改用自定义服务 Worker 文件:
- 编写
src/sw.ts文件:
import { NetworkFirst } from 'workbox-strategies'; import { cleanupOutdatedCaches, precacheAndRoute, clientsClaim } from 'workbox-core'; import { registerRoute } from 'workbox-routing'; import { offlineFallback } from 'workbox-recipes'; declare let self: ServiceWorkerGlobalScope; // 清理旧缓存 cleanupOutdatedCaches(); // 预缓存所有打包资源(包括offline.html) precacheAndRoute(self.__WB_MANIFEST); // 立即接管客户端 self.skipWaiting(); clientsClaim(); // 为导航请求配置网络优先策略 registerRoute( ({ request }) => request.mode === 'navigate', new NetworkFirst({ cacheName: 'navigation-cache', networkTimeoutSeconds: 1, }) ); // 配置离线回退页面 offlineFallback({ pageFallback: '/offline.html', });
- 修改
vite.config.ts切换到injectManifest模式:
import { VitePWA } from 'vite-plugin-pwa'; export default { plugins: [ VitePWA({ strategies: 'injectManifest', srcDir: 'src', filename: 'sw.ts', manifest: { // 你的Manifest配置(示例) name: 'My React PWA', short_name: 'React PWA', start_url: '/', display: 'standalone', background_color: '#fff', theme_color: '#41b883', icons: [ { src: '/icon-192x192.png', sizes: '192x192', type: 'image/png' } ] }, workbox: { globPatterns: ['**/*.{png,svg,ico,txt,js,html,css}'], } }) ] };
关键注意事项
- 确保
offline.html放在项目的public目录下,这样Vite会自动将其打包到dist根目录,且被Workbox纳入预缓存列表。 - 测试前需清空旧的Service Worker缓存(Chrome DevTools → Application → Service Workers → Unregister),再重新构建并部署。
- 离线测试可通过Chrome DevTools的
Application → Service Workers勾选Offline选项验证。
内容的提问来源于stack exchange,提问作者Fed03
相关产品推荐
相关产品推荐

