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:
Jonathan Sykes
2026-09-13 17:42:50 +08:00
parent 5fb863ba25
commit 91dab289c3
8 changed files with 526 additions and 266 deletions

View File

@@ -95,12 +95,32 @@ Local DB file: `server/data/ytplayer.db` (gitignored). `BUILD_TAG` is computed f
"Update available keeps showing" bug.
- `BUILD_TAG` hashes **every** file under `./public` recursively. Don't reduce it
to a file subset; a change to an unlisted shell file would stop busting caches.
- The update banner only shows when a waiting SW exists **and the page already
has a controller** — a first install (fresh visit, or after Settings → Force
refresh unregisters) passes through `waiting` transiently and must not banner.
- "Refresh UI" (`frontend/sw-update.js`): if no worker is waiting yet (banner came
from the `/api/version` poll), it calls `reg.update()`, waits for `installed`,
posts SKIP_WAITING, waits for `controllerchange`, then reloads once.
- **The banner has ONE rule** (`maybeShowUpdateBanner` in app.js): show it only
when the build this page runs differs from `/api/version`. The server stamps
the running build into index.html (`<meta name="ytp-build">`, at request
time like sw.js's BUILD_TAG); the SW caches that index.html with the rest of the
shell, so the meta always describes the code in the tab. The poll, a waiting
worker and the SW_UPDATE_AVAILABLE broadcast are only *prompts to re-check*.
This loop was "fixed" three times by chasing individual triggers — don't add
a trigger that calls `showUpdateBanner()` directly.
- **Refresh UI** (`frontend/sw-update.js`): `refreshShellInPlace()` re-downloads
every file the shell caches hold — cache-busted (`?__ytpfresh=`) so even an
OLD worker's cache-first handler can't answer from its cache, 3 tries per file,
all-or-nothing — and writes them into every versioned shell cache; then it
activates a waiting worker (SKIP_WAITING) if any and reloads once. A failed
download shows an error toast and re-offers later; it never reloads into the
old shell. `checkUpdateOutcome()` verifies after the reload (sessionStorage,
max 3 attempts) instead of looping.
- **Why it kept looping on prod:** the VPS→homelab link is slow and drops
requests. The SW install (`cache.addAll`, all-or-nothing) failed, Refresh UI
reloaded into the old cached shell, and the partial `ytplayer-<tag>` cache
left by the failed install later made activate broadcast "update available"
to pages that were already current. sw.js now precaches with
`cache: 'reload'`, retries each file, and deletes its partial cache on failure.
- Reproduce with the throttling/stalling proxy approach: WebKit (Playwright on
the Windows side) or Chrome over CDP against a scratch copy of the server,
stalling every Nth shell request after "deploying" v2. A fast local link never
shows the bug.
## Cache layout & offline thumbnails
- Three cache families, and the split matters on activate: the **versioned shell