fix: 修复对话页面白屏 — SW 注册缺失导致缓存冲突
根因: 提交 20cdcc7 删除了 main.tsx 中的 SW 注册代码,声称 App.tsx
会调用 registerServiceWorker(),但实际未调用。旧 SW (cyrene-v1) 的
cache-first 策略拦截请求返回不兼容缓存,导致 React 白屏。
修复:
- App.tsx: 在组件挂载时调用 registerServiceWorker()
- sw.js: CACHE_NAME 升级到 cyrene-v2 强制清理旧缓存,增加 SKIP_WAITING
- main.tsx: 修正注释
This commit is contained in:
@@ -1,31 +1,43 @@
|
|||||||
const CACHE_NAME = 'cyrene-v1';
|
const CACHE_NAME = 'cyrene-v2';
|
||||||
const ASSETS_TO_CACHE = [
|
const ASSETS_TO_CACHE = [
|
||||||
'/',
|
'/',
|
||||||
'/index.html',
|
'/index.html',
|
||||||
];
|
];
|
||||||
|
|
||||||
// Install: 缓存核心资源
|
// Install: 缓存核心资源,立即激活
|
||||||
self.addEventListener('install', (event) => {
|
self.addEventListener('install', (event) => {
|
||||||
event.waitUntil(
|
event.waitUntil(
|
||||||
caches.open(CACHE_NAME).then((cache) => {
|
caches.open(CACHE_NAME).then((cache) => {
|
||||||
return cache.addAll(ASSETS_TO_CACHE);
|
return cache.addAll(ASSETS_TO_CACHE);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
// 立即激活新 SW,不等待旧 SW 释放
|
||||||
self.skipWaiting();
|
self.skipWaiting();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Activate: 清理旧缓存
|
// Activate: 清理所有旧版本缓存,立即接管所有页面
|
||||||
self.addEventListener('activate', (event) => {
|
self.addEventListener('activate', (event) => {
|
||||||
event.waitUntil(
|
event.waitUntil(
|
||||||
caches.keys().then((keys) => {
|
caches.keys().then((keys) => {
|
||||||
return Promise.all(
|
return Promise.all(
|
||||||
keys.filter(key => key !== CACHE_NAME).map(key => caches.delete(key))
|
keys.filter(key => key !== CACHE_NAME).map(key => {
|
||||||
|
console.log('[SW] 清理旧缓存:', key);
|
||||||
|
return caches.delete(key);
|
||||||
|
})
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
// 立即接管所有页面(无需刷新)
|
||||||
self.clients.claim();
|
self.clients.claim();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 检测新 SW 更新并通知客户端
|
||||||
|
self.addEventListener('message', (event) => {
|
||||||
|
if (event.data?.type === 'SKIP_WAITING') {
|
||||||
|
self.skipWaiting();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Fetch: 缓存优先策略(对 API 请求使用网络优先)
|
// Fetch: 缓存优先策略(对 API 请求使用网络优先)
|
||||||
self.addEventListener('fetch', (event) => {
|
self.addEventListener('fetch', (event) => {
|
||||||
const url = new URL(event.request.url);
|
const url = new URL(event.request.url);
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { useChat } from '@/hooks/useChat';
|
|||||||
import { useSessionStore, isAdminUser } from '@/store/sessionStore';
|
import { useSessionStore, isAdminUser } from '@/store/sessionStore';
|
||||||
import { useChatStore } from '@/store/chatStore';
|
import { useChatStore } from '@/store/chatStore';
|
||||||
import { fetchMessages } from '@/api/sessions';
|
import { fetchMessages } from '@/api/sessions';
|
||||||
|
import { registerServiceWorker } from '@/hooks/usePWA';
|
||||||
|
|
||||||
/** URL Hash 工具 */
|
/** URL Hash 工具 */
|
||||||
const SESSION_HASH_PREFIX = 'session=';
|
const SESSION_HASH_PREFIX = 'session=';
|
||||||
@@ -44,6 +45,12 @@ export default function App() {
|
|||||||
|
|
||||||
const initializedRef = useRef(false);
|
const initializedRef = useRef(false);
|
||||||
|
|
||||||
|
// ========== PWA Service Worker ==========
|
||||||
|
// 注册 Service Worker(在 main.tsx 移除内联注册后,由 App 组件负责)
|
||||||
|
useEffect(() => {
|
||||||
|
registerServiceWorker();
|
||||||
|
}, []);
|
||||||
|
|
||||||
// ========== URL Hash 路由 ==========
|
// ========== URL Hash 路由 ==========
|
||||||
|
|
||||||
/** 根据 hash 恢复或选择初始会话 */
|
/** 根据 hash 恢复或选择初始会话 */
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ import ReactDOM from 'react-dom/client';
|
|||||||
import App from './App';
|
import App from './App';
|
||||||
import './index.css';
|
import './index.css';
|
||||||
|
|
||||||
// Service Worker 注册已移至 hooks/usePWA.ts 中的 registerServiceWorker(),
|
// Service Worker 注册由 App.tsx 在初始化时调用 registerServiceWorker()(来自 hooks/usePWA.ts)。
|
||||||
// 避免重复注册导致的竞态条件。App.tsx 会在初始化时调用 registerServiceWorker()。
|
// 避免在入口文件直接注册导致的竞态条件。
|
||||||
|
|
||||||
ReactDOM.createRoot(document.getElementById('root')!).render(
|
ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
|
|||||||
Reference in New Issue
Block a user