self.addEventListener("install", (event) => { console.info("Service worker installed.", event) }) self.addEventListener("activate", (event) => { console.info("Service worker activated.", event) }) const CACHE_NAME = "APP-V0" const FILES_TO_CACHE = [FILES_TO_CACHE_LIST] // eslint-disable-line no-undef const FILE_ALIASES = new Map([["/", "/index.html"]]) self.addEventListener("install", async () => { const cache = await caches.open(CACHE_NAME) const additions = cache.addAll(FILES_TO_CACHE) await additions console.info(`Files cached: [\n ${FILES_TO_CACHE.join(`,\n `)}\n]`) }) self.addEventListener("activate", async () => { const oldCacheKeys = (await caches.keys()).filter((key) => key != CACHE_NAME) oldCacheKeys.forEach((key) => caches.delete(key)) }) const normalizePath = (path) => { let normalizedPath = path.replace(/\/+/g, "/") // TODO: Is this a correct replacement for replace(/$(?<!^)\/$/, "") (compatible with Safari)? if (normalizedPath != "/" && normalizedPath.endsWith("/")) { normalizedPath = normalizedPath.slice(0, -1) } normalizedPath = FILE_ALIASES.get(normalizedPath) || normalizedPath return normalizedPath } self.addEventListener("fetch", (event) => { let response = fetch(event.request) const { origin, pathname } = new URL(event.request.url) const path = normalizePath(pathname) if (origin == self.location.origin && FILES_TO_CACHE.includes(path)) { const requestOptions = { ...event.request, mode: "same-origin" } const request = new Request(`${origin}${path}`, requestOptions) response.then(async (response) => { const clone = response.clone() ;(await caches.open(CACHE_NAME)).put(request, clone) }) response = response.catch(async (error) => { return (await caches.match(request)) || Promise.reject(error) }) } event.respondWith(response) })