Full document, spreadsheet, slideshow, and diagram tooling
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge pull request 'fix: break stale service worker cache in Firefox' (#157) from fix/sw-force-break-cache into main

scott 40df4d0e d42a6cc0

+27 -25
+4 -2
public/sw.js
··· 8 8 * - API/WS/health: network-only (never cached) 9 9 */ 10 10 11 - const CACHE_NAME = 'tools-v3'; 11 + const CACHE_NAME = 'tools-v4'; 12 12 13 13 // Static assets to pre-cache on install 14 14 const PRECACHE_URLS = [ ··· 85 85 86 86 async function networkFirst(request) { 87 87 try { 88 - const response = await fetch(request); 88 + // Bypass the browser's HTTP cache to ensure we always hit the server 89 + const freshReq = new Request(request, { cache: 'no-store' }); 90 + const response = await fetch(freshReq); 89 91 if (response.ok) { 90 92 const cache = await caches.open(CACHE_NAME); 91 93 cache.put(request, response.clone());
+6 -5
server/index.ts
··· 431 431 432 432 app.use(express.static(distPath)); 433 433 434 + // HTML pages must not be HTTP-cached — ensures SW networkFirst fetch gets fresh content 435 + const htmlNoCacheHeaders = { 'Cache-Control': 'no-cache, no-store, must-revalidate' }; 436 + 434 437 // SPA fallback: serve the correct index.html for each sub-app 435 - // /docs/:id and /sheets/:id → editor pages 436 - app.get('/docs/:id', (_req: Request, res: Response) => res.sendFile(path.join(distPath, 'docs/index.html'))); 437 - app.get('/sheets/:id', (_req: Request, res: Response) => res.sendFile(path.join(distPath, 'sheets/index.html'))); 438 - // /docs, /sheets, / → landing page (document list + create) 439 - app.get('*', (_req: Request, res: Response) => res.sendFile(path.join(distPath, 'index.html'))); 438 + app.get('/docs/:id', (_req: Request, res: Response) => { res.set(htmlNoCacheHeaders); res.sendFile(path.join(distPath, 'docs/index.html')); }); 439 + app.get('/sheets/:id', (_req: Request, res: Response) => { res.set(htmlNoCacheHeaders); res.sendFile(path.join(distPath, 'sheets/index.html')); }); 440 + app.get('*', (_req: Request, res: Response) => { res.set(htmlNoCacheHeaders); res.sendFile(path.join(distPath, 'index.html')); }); 440 441 441 442 // --- HTTP + HTTPS + WebSocket server --- 442 443 const server = createServer(app);
+5 -6
src/docs/index.html
··· 421 421 <script> 422 422 // Service Worker registration for offline support 423 423 if ('serviceWorker' in navigator) { 424 + var reloading = false; 425 + navigator.serviceWorker.addEventListener('controllerchange', function() { 426 + if (!reloading) { reloading = true; location.reload(); } 427 + }); 424 428 navigator.serviceWorker.register('/sw.js', { updateViaCache: 'none' }).then(function(reg) { 425 - reg.addEventListener('updatefound', function() { 426 - var nw = reg.installing; 427 - if (nw) nw.addEventListener('statechange', function() { 428 - if (nw.state === 'activated') location.reload(); 429 - }); 430 - }); 429 + reg.update().catch(function() {}); 431 430 }).catch(function() {}); 432 431 } 433 432 </script>
+7 -6
src/index.html
··· 176 176 </script> 177 177 <script> 178 178 if ('serviceWorker' in navigator) { 179 + // Reload when a new SW takes control (covers update from any prior version) 180 + var reloading = false; 181 + navigator.serviceWorker.addEventListener('controllerchange', function() { 182 + if (!reloading) { reloading = true; location.reload(); } 183 + }); 179 184 navigator.serviceWorker.register('/sw.js', { updateViaCache: 'none' }).then(function(reg) { 180 - reg.addEventListener('updatefound', function() { 181 - var nw = reg.installing; 182 - if (nw) nw.addEventListener('statechange', function() { 183 - if (nw.state === 'activated') location.reload(); 184 - }); 185 - }); 185 + // Force an immediate update check on every page load 186 + reg.update().catch(function() {}); 186 187 }).catch(function() {}); 187 188 } 188 189 </script>
+5 -6
src/sheets/index.html
··· 361 361 </script> 362 362 <script> 363 363 if ('serviceWorker' in navigator) { 364 + var reloading = false; 365 + navigator.serviceWorker.addEventListener('controllerchange', function() { 366 + if (!reloading) { reloading = true; location.reload(); } 367 + }); 364 368 navigator.serviceWorker.register('/sw.js', { updateViaCache: 'none' }).then(function(reg) { 365 - reg.addEventListener('updatefound', function() { 366 - var nw = reg.installing; 367 - if (nw) nw.addEventListener('statechange', function() { 368 - if (nw.state === 'activated') location.reload(); 369 - }); 370 - }); 369 + reg.update().catch(function() {}); 371 370 }).catch(function() {}); 372 371 } 373 372 </script>