← Назад// Morty's Dashboard — Service Worker v2
// Network-first with offline shell fallback
const CACHE_NAME = 'dashboard-v2';
const SHELL_ASSETS = ['/', '/index.html', '/icon-192.png'];
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(CACHE_NAME).then((cache) => cache.addAll(SHELL_ASSETS))
);
self.skipWaiting();
});
self.addEventListener('activate', (event) => {
event.waitUntil(
caches.keys().then((keys) =>
Promise.all(keys.filter((k) => k !== CACHE_NAME).map((k) => caches.delete(k)))
)
);
self.clients.claim();
});
self.addEventListener('fetch', (event) => {
// Skip non-GET and API calls
if (event.request.method !== 'GET' || event.request.url.includes('/api/')) return;
event.respondWith(
fetch(event.request)
.then((response) => {
// Cache successful responses for static assets
if (response.ok) {
const url = new URL(event.request.url);
if (url.pathname === '/' || url.pathname.startsWith('/assets/') || url.pathname.endsWith('.png')) {
const clone = response.clone();
caches.open(CACHE_NAME).then((c) => c.put(event.request, clone));
}
}
return response;
})
.catch(() => {
// Offline: serve from cache, or return offline page for navigation
return caches.match(event.request).then((cached) => {
if (cached) return cached;
// For navigation requests, serve the shell
if (event.request.mode === 'navigate') {
return caches.match('/index.html');
}
return new Response('Offline', { status: 503, statusText: 'Offline' });
});
})
);
});