const CACHE = "kodaira-parks-v1"; const APP_SHELL = [ "/kodaira-data/parks/", "/manifest.webmanifest", "/icons/icon-192.png", "/icons/icon-512.png", ]; self.addEventListener("install", (event) => { event.waitUntil( caches .open(CACHE) .then((cache) => cache.addAll(APP_SHELL)) .then(() => self.skipWaiting()), ); }); self.addEventListener("activate", (event) => { event.waitUntil( caches .keys() .then((keys) => Promise.all(keys.filter((key) => key !== CACHE).map((key) => caches.delete(key))), ) .then(() => self.clients.claim()), ); }); self.addEventListener("fetch", (event) => { const request = event.request; if (request.method !== "GET") return; const url = new URL(request.url); // OSMのタイルなど外部オリジンのものはキャッシュしない。 if (url.origin !== self.location.origin) return; // ページ遷移はネットワーク優先。オフライン時はキャッシュ→公園ページ。 if (request.mode === "navigate") { event.respondWith( fetch(request) .then((response) => { const copy = response.clone(); caches.open(CACHE).then((cache) => cache.put(request, copy)); return response; }) .catch(() => caches .match(request) .then((cached) => cached || caches.match("/kodaira-data/parks/")), ), ); return; } // それ以外はキャッシュ優先。取得できたらキャッシュを更新する。 event.respondWith( caches.match(request).then((cached) => { const network = fetch(request) .then((response) => { if (response.ok) { const copy = response.clone(); caches.open(CACHE).then((cache) => cache.put(request, copy)); } return response; }) .catch(() => cached); return cached || network; }), ); });