Show the update banner only when the running build differs from the server and make Refresh UI land the new shell on flaky links
This commit is contained in:
@@ -11,12 +11,12 @@
|
||||
* Auto-update flow:
|
||||
* 1. New SW installs alongside the old one and waits (skipWaiting() is NOT
|
||||
* called automatically — see the install handler below).
|
||||
* 2. Client (app.js registerServiceWorker()) notices the waiting worker
|
||||
* and shows the "Update ready" banner.
|
||||
* 3. User clicks "Reload now" → client (applyUpdate() in sw-update.js)
|
||||
* posts SKIP_WAITING to the waiting worker and waits for it to take
|
||||
* control (controllerchange) before reloading — it does NOT unregister
|
||||
* or wipe caches, so the reload doesn't force a brand-new install.
|
||||
* 2. The client (app.js) shows the "Update available" banner only when the
|
||||
* build it is running differs from the server's /api/version buildTag —
|
||||
* a waiting worker or a broadcast is merely a prompt to re-check.
|
||||
* 3. "Refresh UI" (sw-update.js) re-downloads every shell file into every
|
||||
* versioned shell cache (all-or-nothing), activates a waiting worker if
|
||||
* there is one (SKIP_WAITING), and reloads once.
|
||||
* 4. activate: if an older *versioned shell cache* is found (i.e. this
|
||||
* activation is genuinely replacing a previous deploy, not just the
|
||||
* first-ever install of a freshly (re)registered worker), broadcast
|
||||
@@ -68,14 +68,40 @@ const SHELL = [
|
||||
];
|
||||
|
||||
// ---- Install: pre-cache the app shell ----
|
||||
// skipWaiting() is NOT called here — the page activates a waiting worker
|
||||
// from "Refresh UI" (see sw-update.js).
|
||||
self.addEventListener('install', (e) => {
|
||||
e.waitUntil(
|
||||
caches.open(CACHE).then((cache) => cache.addAll(SHELL))
|
||||
// skipWaiting() is NOT called here — we wait for the client to confirm
|
||||
// before activating, so the update banner can appear first.
|
||||
);
|
||||
e.waitUntil(precacheShell());
|
||||
});
|
||||
|
||||
// Fresh requests (`cache: 'reload'` skips the browser HTTP cache, which could
|
||||
// otherwise hand the new worker yesterday's app.js), a few attempts per file
|
||||
// because the homelab link drops requests, and a failed install deletes its
|
||||
// partial cache — a leftover ytplayer-<tag> cache is exactly what activate
|
||||
// uses to decide "this is a genuine update", and it used to re-open the
|
||||
// update banner on pages that were already current.
|
||||
const PRECACHE_ATTEMPTS = 3;
|
||||
async function precacheShell() {
|
||||
const cache = await caches.open(CACHE);
|
||||
try {
|
||||
await Promise.all(SHELL.map(async (url) => {
|
||||
let lastErr = null;
|
||||
for (let attempt = 0; attempt < PRECACHE_ATTEMPTS; attempt++) {
|
||||
try {
|
||||
const res = await fetch(new Request(url, { cache: 'reload' }));
|
||||
if (!res.ok) throw new Error(url + ' → ' + res.status);
|
||||
await cache.put(url, res);
|
||||
return;
|
||||
} catch (err) { lastErr = err; }
|
||||
}
|
||||
throw lastErr;
|
||||
}));
|
||||
} catch (err) {
|
||||
await caches.delete(CACHE);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
// ---- Activate: evict old caches, claim clients, notify about update ----
|
||||
self.addEventListener('activate', (e) => {
|
||||
e.waitUntil((async () => {
|
||||
|
||||
Reference in New Issue
Block a user