Files
cookbook/app/static/sw.js
T

101 lines
3.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// What To Cook? - PWA Service Worker (v1.0.0)
const CACHE_NAME = 'wtc-cache-v1';
const PRECACHE_URLS = [
'/',
'/cookbook',
'/shopping-list',
'/manifest.json',
'/static/cookbook.css',
'/static/icon-192.png',
'/static/icon-512.png'
];
// Install: Pre-cache shell assets
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(CACHE_NAME).then((cache) => {
return cache.addAll(PRECACHE_URLS).catch((err) => {
console.warn('[SW] Pre-caching partial failure, continuing:', err);
});
}).then(() => self.skipWaiting())
);
});
// Activate: Clean up old caches
self.addEventListener('activate', (event) => {
event.waitUntil(
caches.keys().then((cacheNames) => {
return Promise.all(
cacheNames.map((cacheName) => {
if (cacheName !== CACHE_NAME) {
return caches.delete(cacheName);
}
})
);
}).then(() => self.clients.claim())
);
});
// Fetch: Strategy
self.addEventListener('fetch', (event) => {
const req = event.request;
const url = new URL(req.url);
// Skip non-GET and WebSocket/API mutation requests
if (req.method !== 'GET') return;
if (url.pathname.startsWith('/ws/') || url.pathname.startsWith('/api/')) return;
// Navigation requests (HTML pages): Network first, fallback to cache
if (req.mode === 'navigate') {
event.respondWith(
fetch(req).then((response) => {
if (response && response.status === 200) {
const copy = response.clone();
caches.open(CACHE_NAME).then((cache) => cache.put(req, copy));
}
return response;
}).catch(async () => {
const cached = await caches.match(req);
if (cached) return cached;
// If exact page not cached, return home or shopping list if available
if (url.pathname === '/shopping-list') {
const shopCached = await caches.match('/shopping-list');
if (shopCached) return shopCached;
}
const homeCached = await caches.match('/');
if (homeCached) return homeCached;
return new Response('Offline – keine Verbindung vorhanden.', {
status: 503,
headers: { 'Content-Type': 'text/plain; charset=utf-8' }
});
})
);
return;
}
// Static assets: Cache-first, then network update
if (url.pathname.startsWith('/static/') || url.hostname.includes('fonts.googleapis.com') || url.hostname.includes('fonts.gstatic.com')) {
event.respondWith(
caches.match(req).then((cached) => {
if (cached) {
// In background, refresh cache
fetch(req).then((networkRes) => {
if (networkRes && networkRes.status === 200) {
caches.open(CACHE_NAME).then((cache) => cache.put(req, networkRes));
}
}).catch(() => {});
return cached;
}
return fetch(req).then((networkRes) => {
if (networkRes && networkRes.status === 200) {
const copy = networkRes.clone();
caches.open(CACHE_NAME).then((cache) => cache.put(req, copy));
}
return networkRes;
});
})
);
return;
}
});