Spaces:
Running
Running
const STATIC_CACHE = 'static-v3'; | |
const DYNAMIC_CACHE = 'dynamic-v3'; | |
const isHttpGet = (req) => { | |
try { | |
if (!req || req.method !== 'GET') return false; | |
const u = new URL(req.url); | |
return (u.protocol === 'http:' || u.protocol === 'https:'); | |
} catch { return false; } | |
}; | |
const isSameOrigin = (req) => { | |
try { return new URL(req.url).origin === self.location.origin; } catch { return false; } | |
}; | |
self.addEventListener('install', (event) => { | |
event.waitUntil((async () => { | |
const cache = await caches.open(STATIC_CACHE); | |
await cache.addAll(['/','/index.html','/vite.svg']); | |
})()); | |
self.skipWaiting(); | |
}); | |
self.addEventListener('activate', (event) => { | |
event.waitUntil((async () => { | |
// If you enabled navigationPreload in page code, either keep it: | |
// await self.registration.navigationPreload.enable(); | |
// or disable to remove the warning: | |
try { await self.registration.navigationPreload.disable(); } catch {} | |
const names = await caches.keys(); | |
await Promise.all(names.map((n) => (n === STATIC_CACHE || n === DYNAMIC_CACHE) ? null : caches.delete(n))); | |
await self.clients.claim(); | |
})()); | |
}); | |
self.addEventListener('fetch', (event) => { | |
const req = event.request; | |
// Ignore non-http(s) or non-GET (extensions, blob:, data:, etc.) | |
if (!isHttpGet(req)) return; | |
const url = new URL(req.url); | |
// Handle navigations (SPA shell) + optional preload | |
if (req.mode === 'navigate') { | |
event.respondWith((async () => { | |
// If preload is enabled, prefer it | |
const pre = await event.preloadResponse; | |
if (pre) return pre; | |
try { | |
const net = await fetch(req); | |
return net; | |
} catch { | |
const cached = await caches.match('/index.html'); | |
return cached || Response.error(); | |
} | |
})()); | |
return; | |
} | |
// API: network-first, cache successful same-origin GETs | |
if (url.pathname.startsWith('/api/')) { | |
event.respondWith((async () => { | |
try { | |
const resp = await fetch(req); | |
if (resp.ok && isSameOrigin(req)) { | |
try { | |
const c = await caches.open(DYNAMIC_CACHE); | |
await c.put(req, resp.clone()); | |
} catch {} | |
} | |
return resp; | |
} catch { | |
const cached = await caches.match(req); | |
return cached || Response.error(); | |
} | |
})()); | |
return; | |
} | |
// Assets (script/style/image/font): cache-first | |
const dest = req.destination; | |
const isAsset = dest === 'script' || dest === 'style' || dest === 'image' || dest === 'font'; | |
if (isAsset) { | |
event.respondWith((async () => { | |
const hit = await caches.match(req); | |
if (hit) return hit; | |
const resp = await fetch(req); | |
if (resp.ok && isSameOrigin(req)) { | |
try { | |
const c = await caches.open(STATIC_CACHE); | |
await c.put(req, resp.clone()); | |
} catch {} | |
} | |
return resp; | |
})()); | |
return; | |
} | |
// Default: network-first with safe cache | |
event.respondWith((async () => { | |
try { | |
const resp = await fetch(req); | |
if (resp.ok && isSameOrigin(req)) { | |
try { | |
const c = await caches.open(DYNAMIC_CACHE); | |
await c.put(req, resp.clone()); | |
} catch {} | |
} | |
return resp; | |
} catch { | |
const cached = await caches.match(req); | |
return cached || Response.error(); | |
} | |
})()); | |
}); | |