76 lines
2.3 KiB
JavaScript
76 lines
2.3 KiB
JavaScript
// The Dojo Bay — service worker.
|
|
// Strategy:
|
|
// * app shell (html, css, js, fonts, icons, content) is precached and served
|
|
// cache-first, so the installed PWA opens instantly and works offline;
|
|
// * live data (data/*.json) and the Markdown text (content/*.md) are fetched
|
|
// network-first so a connected client always sees the latest snapshot,
|
|
// falling back to cache when offline.
|
|
// Bump CACHE when you ship new assets to retire the old cache.
|
|
const CACHE = "dojobay-v2";
|
|
|
|
const SHELL = [
|
|
"./",
|
|
"index.html",
|
|
"assets/css/styles.css",
|
|
"assets/js/app.js",
|
|
"assets/js/markdown.js",
|
|
"assets/js/qrcode.js",
|
|
"assets/fonts/archivo.woff2",
|
|
"assets/fonts/hanken-grotesk.woff2",
|
|
"assets/fonts/jetbrains-mono.woff2",
|
|
"favicon.svg",
|
|
"manifest.json",
|
|
"assets/icons/192x192.png",
|
|
"assets/icons/512x512.png",
|
|
"content/about.md",
|
|
"content/faq.md",
|
|
"content/disclaimer.md",
|
|
];
|
|
|
|
self.addEventListener("install", (e) => {
|
|
e.waitUntil(
|
|
caches.open(CACHE)
|
|
.then((c) => Promise.allSettled(SHELL.map((u) => c.add(u))))
|
|
.then(() => self.skipWaiting())
|
|
);
|
|
});
|
|
|
|
self.addEventListener("activate", (e) => {
|
|
e.waitUntil(
|
|
caches.keys()
|
|
.then((keys) => Promise.all(keys.filter((k) => k !== CACHE).map((k) => caches.delete(k))))
|
|
.then(() => self.clients.claim())
|
|
);
|
|
});
|
|
|
|
self.addEventListener("fetch", (e) => {
|
|
const req = e.request;
|
|
if (req.method !== "GET") return;
|
|
const url = new URL(req.url);
|
|
if (url.origin !== self.location.origin) return; // ignore cross-origin
|
|
|
|
// Cache-first ONLY for large, rarely-changing static assets (fonts, icons,
|
|
// images). Everything else (HTML, JS, CSS, JSON data, Markdown) is
|
|
// network-first, so a deploy propagates on the next load and the cache is
|
|
// only an offline fallback. This avoids stale code surviving a deploy.
|
|
const cacheFirst = /\.(woff2|png|svg|ico)$/.test(url.pathname);
|
|
|
|
if (!cacheFirst) {
|
|
e.respondWith(
|
|
fetch(req)
|
|
.then((res) => { const copy = res.clone(); caches.open(CACHE).then((c) => c.put(req, copy)); return res; })
|
|
.catch(() => caches.match(req))
|
|
);
|
|
} else {
|
|
e.respondWith(
|
|
caches.match(req).then((hit) =>
|
|
hit || fetch(req).then((res) => {
|
|
const copy = res.clone();
|
|
caches.open(CACHE).then((c) => c.put(req, copy));
|
|
return res;
|
|
})
|
|
)
|
|
);
|
|
}
|
|
});
|