Files
Lageplan/public/sw.js

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())
)
})