Fix stale queue page: switch pages to network-first in service worker
The service worker was using cache-first for ALL non-API routes, including page routes like /queue, /capture, /browser. This meant the browser kept serving old cached HTML with old inline JS even after deploys, which is why the queue file list never updated (old JS was running, silently crashing on API mismatches). Now only /static/ assets use cache-first (they're versioned via SW cache bumps). All pages and API calls use network-first with cache as offline fallback. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
121
app/static/sw.js
121
app/static/sw.js
@@ -1,9 +1,9 @@
|
|||||||
// NextSnap Service Worker
|
// NextSnap Service Worker
|
||||||
// Provides offline-first caching for the app shell
|
// Provides offline-first caching for the app shell
|
||||||
|
|
||||||
const CACHE_VERSION = 'nextsnap-v18';
|
const CACHE_VERSION = 'nextsnap-v19';
|
||||||
const APP_SHELL_CACHE = 'nextsnap-shell-v14';
|
const APP_SHELL_CACHE = 'nextsnap-shell-v15';
|
||||||
const RUNTIME_CACHE = 'nextsnap-runtime-v14';
|
const RUNTIME_CACHE = 'nextsnap-runtime-v15';
|
||||||
|
|
||||||
// Assets to cache on install
|
// Assets to cache on install
|
||||||
const APP_SHELL_ASSETS = [
|
const APP_SHELL_ASSETS = [
|
||||||
@@ -62,91 +62,72 @@ self.addEventListener('activate', (event) => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Fetch event - cache-first for static assets, network-first for API
|
// Fetch event - route requests to appropriate caching strategy
|
||||||
self.addEventListener('fetch', (event) => {
|
self.addEventListener('fetch', (event) => {
|
||||||
const { request } = event;
|
const { request } = event;
|
||||||
const url = new URL(request.url);
|
const url = new URL(request.url);
|
||||||
|
|
||||||
// Skip non-GET requests
|
// Skip non-GET requests (uploads, form posts, etc.)
|
||||||
if (request.method !== 'GET') {
|
if (request.method !== 'GET') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// API requests - network-first with offline fallback
|
// Static assets (/static/) - cache-first (versioned via SW cache bump)
|
||||||
if (url.pathname.startsWith('/api/')) {
|
if (url.pathname.startsWith('/static/')) {
|
||||||
event.respondWith(
|
event.respondWith(
|
||||||
fetch(request)
|
caches.match(request)
|
||||||
.then((response) => {
|
.then((cachedResponse) => {
|
||||||
// Clone response for cache
|
if (cachedResponse) {
|
||||||
const responseClone = response.clone();
|
return cachedResponse;
|
||||||
|
|
||||||
// Only cache successful responses (not errors or auth failures)
|
|
||||||
if (response.status === 200) {
|
|
||||||
caches.open(RUNTIME_CACHE).then((cache) => {
|
|
||||||
// Don't cache file uploads or large responses
|
|
||||||
if (!url.pathname.includes('/upload') &&
|
|
||||||
!url.pathname.includes('/thumbnail')) {
|
|
||||||
cache.put(request, responseClone);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
return fetch(request)
|
||||||
return response;
|
.then((response) => {
|
||||||
})
|
if (!response || response.status !== 200) {
|
||||||
.catch(() => {
|
return response;
|
||||||
// Network failed - try cache, then offline response
|
|
||||||
return caches.match(request)
|
|
||||||
.then((cachedResponse) => {
|
|
||||||
if (cachedResponse) {
|
|
||||||
return cachedResponse;
|
|
||||||
}
|
}
|
||||||
|
const responseClone = response.clone();
|
||||||
// Return offline fallback for API
|
caches.open(APP_SHELL_CACHE).then((cache) => {
|
||||||
return new Response(
|
cache.put(request, responseClone);
|
||||||
JSON.stringify({
|
});
|
||||||
error: 'offline',
|
return response;
|
||||||
message: 'You are offline. This feature requires connectivity.'
|
})
|
||||||
}),
|
.catch(() => new Response('Offline', { status: 503 }));
|
||||||
{
|
|
||||||
status: 503,
|
|
||||||
statusText: 'Service Unavailable',
|
|
||||||
headers: { 'Content-Type': 'application/json' }
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Static assets - cache-first strategy
|
// Everything else (pages, API) - network-first with cache fallback
|
||||||
event.respondWith(
|
event.respondWith(
|
||||||
caches.match(request)
|
fetch(request)
|
||||||
.then((cachedResponse) => {
|
.then((response) => {
|
||||||
if (cachedResponse) {
|
// Cache successful GET responses for offline fallback
|
||||||
return cachedResponse;
|
if (response.status === 200) {
|
||||||
}
|
const responseClone = response.clone();
|
||||||
|
caches.open(RUNTIME_CACHE).then((cache) => {
|
||||||
// Not in cache - fetch from network and cache it
|
// Don't cache file uploads or large binary responses
|
||||||
return fetch(request)
|
if (!url.pathname.includes('/upload') &&
|
||||||
.then((response) => {
|
!url.pathname.includes('/thumbnail')) {
|
||||||
// Don't cache non-successful responses
|
|
||||||
if (!response || response.status !== 200 || response.type === 'error') {
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clone response for cache
|
|
||||||
const responseClone = response.clone();
|
|
||||||
|
|
||||||
caches.open(RUNTIME_CACHE).then((cache) => {
|
|
||||||
cache.put(request, responseClone);
|
cache.put(request, responseClone);
|
||||||
});
|
}
|
||||||
|
});
|
||||||
return response;
|
}
|
||||||
})
|
return response;
|
||||||
.catch(() => {
|
})
|
||||||
// Network failed and not in cache
|
.catch(() => {
|
||||||
// For HTML pages, could return offline page here
|
// Network failed - try cache
|
||||||
|
return caches.match(request)
|
||||||
|
.then((cachedResponse) => {
|
||||||
|
if (cachedResponse) {
|
||||||
|
return cachedResponse;
|
||||||
|
}
|
||||||
|
// No cache - return offline response
|
||||||
|
if (url.pathname.startsWith('/api/')) {
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({ error: 'offline', message: 'You are offline.' }),
|
||||||
|
{ status: 503, headers: { 'Content-Type': 'application/json' } }
|
||||||
|
);
|
||||||
|
}
|
||||||
return new Response('Offline', { status: 503 });
|
return new Response('Offline', { status: 503 });
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user