/* eslint-disable no-var */ import { build, files, version } from '$service-worker'; // Code mostly comes from: https://dev.to/100lvlmaster/create-a-pwa-with-sveltekit-svelte-a36 // With some modifications done by someone in the comments const worker = (self as unknown) as ServiceWorkerGlobalScope; const STATIC_CACHE_NAME = `cache${version}` const APP_CACHE_NAME = `offline${version}`; // Hardcoded bunch of routes to always preemptively cache const routes = ["/", "/about"]; // Hardcoded list of other assets to always preemptively cache //const custom_assets = [ // //"https://fonts.googleapis.com/css2?family=Montserrat:wght@200&family=Roboto+Flex:opsz,wght@8..144,300;8..144,400;8..144,500&family=Roboto+Slab&display=swap" // "https://quenten.nl/favicon.png" //Just there as a placeholder //]; // Adds the domain to the file path, making it a full name const addDomain = (assets: string[]) => assets.map((f) => self.location.origin + f); // build is an array of all files generated by the bundler // files is an array of all files in the static dir const ourAssets = addDomain([ ...files, ...build, ...routes ]); const to_cache = [ ...ourAssets, // ...custom_assets ] const staticAssets = new Set(to_cache); worker.addEventListener("install", (event) => { event.waitUntil( caches .open(STATIC_CACHE_NAME) .then((cache) => { to_cache.forEach((item) => { return cache.add(item) }) return }) .then(() => { worker.skipWaiting(); }) ); }); worker.addEventListener("activate", (event) => { event.waitUntil( caches.keys() .then(async (keys) => { // Delete old caches for (const key of keys) { if (key !== STATIC_CACHE_NAME && key !== APP_CACHE_NAME) await caches.delete(key); } console.log("old caches deleted") worker.clients.claim(); }) .then(() => console.log("Activated")) ) }) // Fetch the asset from the network and store it in the cache // Falls back to the cache if the user is offline async function fetchAndCache(request: Request) { const cache = await caches.open(APP_CACHE_NAME); try { const response = await fetch(request); cache.put(request, response.clone()); return response; } catch (err) { // if the user is offline, the request will fail const response = await cache.match(request); if (response) return response; // if not in cache, throw error anyway throw err; } } worker.addEventListener("fetch", (event) => { if (event.request.method !== "GET") return; if (new URL(event.request.url).hostname === "api.quenten.nl") return; //console.log("fetch event intercepted") // Range requests are unsupported for some reason if (event.request.headers.has("range")) { // Check if in the cache, and return if it is there, // otherwise let the request go through and start a new request // in the background without the range header console.log("Request has a Range header (HTTP 206). Checking if it's in cache") event.respondWith( (async () => { const url = new URL(event.request.url); const isStaticAsset = staticAssets.has(url.href); const cachedAsset = isStaticAsset && (await caches.match(event.request, {ignoreVary: true})); return cachedAsset || (await fetch(event.request,)) })() ); // Also put the thing in cache for next time! const newRequest = new Request(event.request.url) fetchAndCache(newRequest); return } const url = new URL(event.request.url); // Don't try to cache protocols other than http/https const isHttp = url.protocol.startsWith("http"); const isStaticAsset = staticAssets.has(url.href); const isDev = url.host === self.location.host; const skipBecauseUncached = event.request.cache === 'only-if-cached' && !isStaticAsset; if (isHttp && !skipBecauseUncached) { event.respondWith( (async () => { // always serve static files and bundler-generated assets from cache. // if your application has other URLs with data that will never change, // set this variable to true for them, and they will only be fetched once. const cachedAsset = isStaticAsset && (await caches.match(event.request, {ignoreVary: true})); return cachedAsset || fetchAndCache(event.request); })() ) } })