SW: non-disruptive update — drop skipWaiting/claim (post-deploy boot stall)
Telemetry isolated the last boot-slow source (id9): warm edge, fast shell (60ms), but chunks took 2.6-4.7s on the LAN-fast dev box, 26min post-deploy — i.e. NOT network/origin. Cause: on the first load of a new build the new SW ran skipWaiting()+clients.claim(), activating mid-boot — deleting the old cache and seizing the loading page, yanking the cache from under the ~16 in-flight chunk requests (the sz0 + clustered-start + staggered-finish signature). Fix (Codex-approved): remove skipWaiting() and clients.claim() so a new worker installs quietly and takes control on the NEXT navigation, never mid-boot. The post-deploy first load then completes under the stable old worker (cache intact) against the warmed edge. Cache cleanup stays in activate (now runs only at the deferred, safe activation); old immutable chunks live 14 days at the origin regardless, so a slightly-behind worker still loads safely. Trade-off — SW/shell update applies one navigation later — is fine: the shell is edge-cached and the SW's only job is offline/slow-network fallback. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -40,17 +40,23 @@ function isMutablePath(p) {
|
||||
|
||||
self.addEventListener('install', (event) => {
|
||||
// Best-effort: grab the app shell as an offline fallback. No bulk precache.
|
||||
event.waitUntil(
|
||||
caches.open(CACHE).then((c) => c.add('/').catch(() => {})).then(() => self.skipWaiting())
|
||||
);
|
||||
// Deliberately NO skipWaiting(): a new worker installs quietly and waits, so
|
||||
// it never seizes a page that's mid-boot. It takes control on the next
|
||||
// navigation, when the old worker has no clients — the post-deploy first-load
|
||||
// then completes under the stable old worker (with its cache intact) against
|
||||
// the warmed edge, instead of having its cache yanked mid-load.
|
||||
event.waitUntil(caches.open(CACHE).then((c) => c.add('/').catch(() => {})));
|
||||
});
|
||||
|
||||
self.addEventListener('activate', (event) => {
|
||||
// Runs only when this worker actually activates (next navigation, never
|
||||
// mid-boot), so deleting old version caches here is safe — and old immutable
|
||||
// chunks live on at the origin for a 14-day grace window regardless. No
|
||||
// clients.claim(): pages adopt this worker on their own next navigation.
|
||||
event.waitUntil(
|
||||
caches
|
||||
.keys()
|
||||
.then((keys) => Promise.all(keys.filter((k) => k !== CACHE).map((k) => caches.delete(k))))
|
||||
.then(() => self.clients.claim())
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user