mirror of
https://github.com/storytold/effectcraft.git
synced 2026-10-30 04:57:54 -06:00
A startup key (last, empty or demo) chooses the project the page opens on load. empty restores the last visit's project and otherwise starts blank, never with the demo; demo always opens the demo project; last, or no key, is the current behaviour. ?empty and ?demo still win. The config file is fetched once per page load and the service worker never caches it.
50 lines
1.9 KiB
JavaScript
50 lines
1.9 KiB
JavaScript
// EffectCraft service worker: the app works offline once loaded, and installs as an app.
|
|
//
|
|
// `cargo xtask web` fills in the build's file list and version. Every file is precached into a
|
|
// cache named after the version, served cache-first (responses keep the server's headers, so
|
|
// the page stays cross-origin isolated: COOP/COEP), and old versions are dropped once the new
|
|
// one activates. Anything else same-origin is fetched from the network and cached for next time,
|
|
// except the config file, which must stay live.
|
|
const VERSION = "__EC_VERSION__";
|
|
const FILES = __EC_FILES__;
|
|
const CACHE = `effectcraft-${VERSION}`;
|
|
|
|
self.addEventListener("install", (event) => {
|
|
event.waitUntil(
|
|
caches
|
|
.open(CACHE)
|
|
.then((c) => c.addAll(FILES.map((f) => new Request(f, { cache: "reload" }))))
|
|
.then(() => self.skipWaiting()),
|
|
);
|
|
});
|
|
|
|
self.addEventListener("activate", (event) => {
|
|
event.waitUntil(
|
|
caches
|
|
.keys()
|
|
.then((keys) => Promise.all(keys.filter((k) => k.startsWith("effectcraft-") && k !== CACHE).map((k) => caches.delete(k))))
|
|
.then(() => self.clients.claim()),
|
|
);
|
|
});
|
|
|
|
self.addEventListener("fetch", (event) => {
|
|
const req = event.request;
|
|
const url = new URL(req.url);
|
|
if (req.method !== "GET" || url.origin !== self.location.origin) return;
|
|
if (url.pathname.endsWith("/effectcraft-config.json")) return;
|
|
event.respondWith(
|
|
(async () => {
|
|
const cache = await caches.open(CACHE).catch(() => null);
|
|
if (cache) {
|
|
// The page itself regardless of its query (?empty, ?demo…).
|
|
const key = req.mode === "navigate" ? new URL("./", self.registration.scope).href : req;
|
|
const hit = await cache.match(key, { ignoreSearch: req.mode === "navigate" }).catch(() => null);
|
|
if (hit) return hit;
|
|
}
|
|
const res = await fetch(req);
|
|
if (cache && res.ok && res.type === "basic") void cache.put(req, res.clone()).catch(() => {});
|
|
return res;
|
|
})(),
|
|
);
|
|
});
|