Spaces:
Sleeping
Sleeping
Upload 67 files
Browse files- App.tsx +39 -1
- server.js +13 -2
- vite.config.ts +1 -0
App.tsx
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
|
|
| 1 |
import React, { useState, useEffect, useRef } from 'react';
|
| 2 |
import { Sidebar } from './components/Sidebar';
|
| 3 |
import { Header } from './components/Header';
|
|
@@ -126,6 +127,43 @@ const AppContent: React.FC = () => {
|
|
| 126 |
const [loading, setLoading] = useState(true);
|
| 127 |
const [sidebarOpen, setSidebarOpen] = useState(false);
|
| 128 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 129 |
useEffect(() => {
|
| 130 |
const initApp = async () => {
|
| 131 |
api.init();
|
|
@@ -237,4 +275,4 @@ const App: React.FC = () => {
|
|
| 237 |
);
|
| 238 |
};
|
| 239 |
|
| 240 |
-
export default App;
|
|
|
|
| 1 |
+
|
| 2 |
import React, { useState, useEffect, useRef } from 'react';
|
| 3 |
import { Sidebar } from './components/Sidebar';
|
| 4 |
import { Header } from './components/Header';
|
|
|
|
| 127 |
const [loading, setLoading] = useState(true);
|
| 128 |
const [sidebarOpen, setSidebarOpen] = useState(false);
|
| 129 |
|
| 130 |
+
// --- Auto-Update Logic ---
|
| 131 |
+
useEffect(() => {
|
| 132 |
+
// 1. Force reload page when Service Worker updates (controller change)
|
| 133 |
+
// This happens automatically due to 'registerType: autoUpdate' in vite config,
|
| 134 |
+
// but the window needs to reload to use the new SW.
|
| 135 |
+
const handleControllerChange = () => {
|
| 136 |
+
console.log("🔄 App updated, reloading...");
|
| 137 |
+
window.location.reload();
|
| 138 |
+
};
|
| 139 |
+
|
| 140 |
+
// 2. Check for updates on visibility change (e.g. user comes back to tab)
|
| 141 |
+
const checkForUpdates = () => {
|
| 142 |
+
if ('serviceWorker' in navigator) {
|
| 143 |
+
navigator.serviceWorker.ready.then(registration => {
|
| 144 |
+
registration.update();
|
| 145 |
+
}).catch(() => {});
|
| 146 |
+
}
|
| 147 |
+
};
|
| 148 |
+
|
| 149 |
+
if ('serviceWorker' in navigator) {
|
| 150 |
+
navigator.serviceWorker.addEventListener('controllerchange', handleControllerChange);
|
| 151 |
+
document.addEventListener('visibilitychange', () => {
|
| 152 |
+
if (document.visibilityState === 'visible') {
|
| 153 |
+
checkForUpdates();
|
| 154 |
+
}
|
| 155 |
+
});
|
| 156 |
+
// Initial check
|
| 157 |
+
checkForUpdates();
|
| 158 |
+
}
|
| 159 |
+
|
| 160 |
+
return () => {
|
| 161 |
+
if ('serviceWorker' in navigator) {
|
| 162 |
+
navigator.serviceWorker.removeEventListener('controllerchange', handleControllerChange);
|
| 163 |
+
}
|
| 164 |
+
};
|
| 165 |
+
}, []);
|
| 166 |
+
|
| 167 |
useEffect(() => {
|
| 168 |
const initApp = async () => {
|
| 169 |
api.init();
|
|
|
|
| 275 |
);
|
| 276 |
};
|
| 277 |
|
| 278 |
+
export default App;
|
server.js
CHANGED
|
@@ -31,10 +31,21 @@ app.use(compression({
|
|
| 31 |
|
| 32 |
app.use(cors());
|
| 33 |
app.use(bodyParser.json({ limit: '50mb' }));
|
|
|
|
|
|
|
| 34 |
app.use(express.static(path.join(__dirname, 'dist'), {
|
| 35 |
setHeaders: (res, filePath) => {
|
| 36 |
-
|
| 37 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 38 |
}
|
| 39 |
}));
|
| 40 |
|
|
|
|
| 31 |
|
| 32 |
app.use(cors());
|
| 33 |
app.use(bodyParser.json({ limit: '50mb' }));
|
| 34 |
+
|
| 35 |
+
// 静态资源托管配置优化
|
| 36 |
app.use(express.static(path.join(__dirname, 'dist'), {
|
| 37 |
setHeaders: (res, filePath) => {
|
| 38 |
+
// 关键修复:入口文件、Service Worker 和 Manifest 必须禁止缓存,确保每次都获取最新版本
|
| 39 |
+
if (
|
| 40 |
+
filePath.endsWith('.html') ||
|
| 41 |
+
filePath.endsWith('sw.js') ||
|
| 42 |
+
filePath.endsWith('manifest.webmanifest')
|
| 43 |
+
) {
|
| 44 |
+
res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
|
| 45 |
+
} else {
|
| 46 |
+
// 其他带 Hash 的静态资源可以强缓存 1 年
|
| 47 |
+
res.setHeader('Cache-Control', 'public, max-age=31536000, immutable');
|
| 48 |
+
}
|
| 49 |
}
|
| 50 |
}));
|
| 51 |
|
vite.config.ts
CHANGED
|
@@ -38,6 +38,7 @@ export default defineConfig({
|
|
| 38 |
]
|
| 39 |
},
|
| 40 |
workbox: {
|
|
|
|
| 41 |
// 缓存策略配置,确保 API 请求不被过度缓存,但静态资源被缓存
|
| 42 |
globPatterns: ['**/*.{js,css,html,ico,png,svg}'],
|
| 43 |
runtimeCaching: [
|
|
|
|
| 38 |
]
|
| 39 |
},
|
| 40 |
workbox: {
|
| 41 |
+
cleanupOutdatedCaches: true, // 关键:自动清理过期的缓存文件
|
| 42 |
// 缓存策略配置,确保 API 请求不被过度缓存,但静态资源被缓存
|
| 43 |
globPatterns: ['**/*.{js,css,html,ico,png,svg}'],
|
| 44 |
runtimeCaching: [
|