SCGR's picture
sw
bf81892
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();
}
})());
});