95 lines
2.8 KiB
JavaScript
95 lines
2.8 KiB
JavaScript
const TILE_CACHE = 'lageplan-tiles-v2'
|
|
const STATIC_CACHE = 'lageplan-static-v2'
|
|
const APP_CACHE = 'lageplan-app-v2'
|
|
|
|
// Pre-cache essential app shell on install
|
|
self.addEventListener('install', (event) => {
|
|
event.waitUntil(
|
|
caches.open(APP_CACHE).then((cache) =>
|
|
cache.addAll([
|
|
'/app',
|
|
'/logo.svg',
|
|
'/logo-icon.png',
|
|
'/manifest.json',
|
|
]).catch(() => {})
|
|
)
|
|
)
|
|
self.skipWaiting()
|
|
})
|
|
|
|
// Cache strategy: Network First for API, Cache First for tiles, Stale While Revalidate for static assets
|
|
self.addEventListener('fetch', (event) => {
|
|
const url = event.request.url
|
|
const { pathname } = new URL(url)
|
|
|
|
// Skip non-GET requests
|
|
if (event.request.method !== 'GET') return
|
|
|
|
// API requests: network only (don't cache dynamic data)
|
|
if (pathname.startsWith('/api/')) return
|
|
|
|
// Cache map tiles from OpenStreetMap (Cache First)
|
|
if (url.includes('tile.openstreetmap.org') || url.includes('api.maptiler.com')) {
|
|
event.respondWith(
|
|
caches.open(TILE_CACHE).then((cache) =>
|
|
cache.match(event.request).then((cached) => {
|
|
if (cached) return cached
|
|
return fetch(event.request).then((response) => {
|
|
if (response.ok) {
|
|
cache.put(event.request, response.clone())
|
|
}
|
|
return response
|
|
}).catch(() => new Response('', { status: 503 }))
|
|
})
|
|
)
|
|
)
|
|
return
|
|
}
|
|
|
|
// Static assets (JS, CSS, images): Stale While Revalidate
|
|
if (pathname.match(/\.(js|css|png|jpg|jpeg|svg|ico|woff2?)$/)) {
|
|
event.respondWith(
|
|
caches.open(STATIC_CACHE).then((cache) =>
|
|
cache.match(event.request).then((cached) => {
|
|
const fetchPromise = fetch(event.request).then((response) => {
|
|
if (response.ok) cache.put(event.request, response.clone())
|
|
return response
|
|
}).catch(() => cached || new Response('', { status: 503 }))
|
|
return cached || fetchPromise
|
|
})
|
|
)
|
|
)
|
|
return
|
|
}
|
|
|
|
// App pages: Network First with cache fallback
|
|
if (pathname === '/app' || pathname === '/' || pathname.startsWith('/app')) {
|
|
event.respondWith(
|
|
fetch(event.request).then((response) => {
|
|
if (response.ok) {
|
|
const clone = response.clone()
|
|
caches.open(APP_CACHE).then((cache) => cache.put(event.request, clone))
|
|
}
|
|
return response
|
|
}).catch(() =>
|
|
caches.match(event.request).then((cached) => cached || caches.match('/app'))
|
|
)
|
|
)
|
|
return
|
|
}
|
|
})
|
|
|
|
// Clean old caches on activation
|
|
self.addEventListener('activate', (event) => {
|
|
const currentCaches = [TILE_CACHE, STATIC_CACHE, APP_CACHE]
|
|
event.waitUntil(
|
|
caches.keys().then((keys) =>
|
|
Promise.all(
|
|
keys
|
|
.filter((k) => !currentCaches.includes(k))
|
|
.map((k) => caches.delete(k))
|
|
)
|
|
).then(() => self.clients.claim())
|
|
)
|
|
})
|