Files
rhinelab-ui/scripts/pwa-worker.js
T

62 lines
2.6 KiB
JavaScript

/* The build replaces both tokens; this file is never registered in development. */
const VERSION = __CACHE_VERSION__;
const FILES = __PRECACHE_FILES__;
const PREFIX = `rhine-lab:${new URL(self.registration.scope).pathname}:`;
const CACHE = PREFIX + VERSION;
const urls = FILES.map(path => new URL(path, self.registration.scope).href);
const allowed = new Set(urls);
const index = new URL("index.html", self.registration.scope).href;
self.addEventListener("install", event => {
event.waitUntil((async () => {
try {
const cache = await caches.open(CACHE);
// Limit connections so a complete font family does not flood the page.
// Keep successful files private until every resource is present; failure
// still deletes this entire release and leaves the active release intact.
let next = 0;
const workers = Array.from({ length: 6 }, async () => {
while (next < urls.length) {
const url = urls[next++];
const immutable = /\/fonts\/misans-webfont-4\.3\.1\//.test(url) || /\/assets\/archive-(cassette|assembly)\.[a-f0-9]{16}\.glb$/.test(url);
await cache.add(new Request(url, { cache: immutable ? "default" : "no-cache" }));
}
});
const results = await Promise.allSettled(workers);
const failure = results.find(result => result.status === "rejected");
if (failure) throw failure.reason;
} catch (error) {
await caches.delete(CACHE);
throw error;
}
})());
});
self.addEventListener("activate", event => {
event.waitUntil((async () => {
for (const key of await caches.keys())
if (key.startsWith(PREFIX) && key !== CACHE) await caches.delete(key);
await self.clients.claim();
})());
});
self.addEventListener("message", event => {
if (event.data?.type === "RHINE_APPLY_UPDATE") event.waitUntil(self.skipWaiting());
});
self.addEventListener("fetch", event => {
if (event.request.method !== "GET") return;
const url = new URL(event.request.url);
if (url.origin !== self.location.origin) return;
url.search = "";
url.hash = "";
const navigation = event.request.mode === "navigate" &&
(url.href === self.registration.scope || url.href === index);
const key = navigation ? index : url.href;
if (!allowed.has(key)) return;
event.respondWith((async () => {
const cache = await caches.open(CACHE);
// HTML, hashed bundles and stable model URLs come from the same release.
// A new release stays waiting until the user chooses to restart or exits.
const cached = await cache.match(key);
return cached ?? fetch(event.request);
})());
});