feat: SW install robustness — runtime-cached glyphs + one-shot recovery (#27, #28)#41
Merged
Merged
Conversation
…re-SW map loads #28 — service-worker install robustness: - Exclude basemap-assets/fonts/** (768 glyph-range .pbf files) from the precache manifest via globIgnores: 791 entries / ~44.0 MB -> 24 entries / ~33.3 MB, so the install fits the browser's install-event budget even on slow connections. - Serve glyphs from a dedicated runtime CacheFirst route in sw.ts (sailcommand-glyphs-v1), scoped same-origin + fonts path + .pbf so it can never match the Open-Meteo origin or the .pmtiles Range route, which stays the first registration. - Emit dist/glyph-manifest.json at build time (vite plugin) and backfill un-cached ranges from the window side (glyphWarmup.ts) once the SW controls the page and the app is idle — never from install/activate waitUntil. Failures are non-fatal and retried next visit; the warm-up never runs offline. - Offline e2e stays honest (server-kill pattern): waits on the warm-up's deterministic completion signal + runtime cache convergence before the server dies, probes a glyph range offline (200 from cache), and asserts zero console errors across the whole offline phase. Built-output guards now parse the injected precache manifest (no fonts entries, < 400 entries) and cross-check glyph-manifest.json against dist. #27 — one-shot recovery from gzip-stamped Range responses: - swRecovery.ts records MapLibre errors that happen while the page is not yet SW-controlled and, on the FIRST controllerchange, reloads the page exactly once (sessionStorage guard set before reloading; never arms when already controlled at load; never loops; MapView's console.error and error banner behavior unchanged). Refs #27, #28. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… size comment Review round 1 on the #27/#28 change set, two Minors: - M1: glyphs.ts documented that a GLYPH_CACHE_NAME bump requires deleting the old cache, but nothing implemented it — cleanupOutdatedCaches() only manages precache caches. sw.ts now deletes retired sailcommand-glyphs-* caches in an activate waitUntil (bounded: one caches.keys() + targeted deletes; clientsClaim()'s own listener still claims immediately). The deletion predicate isRetiredGlyphCache() lives in glyphs.ts as a pure function with unit tests (sw.ts has no unit-test harness), alongside tests pinning isGlyphPath()'s route scoping. - M2: main.tsx storage-persist comment updated from the stale "~44 MB" to ~33 MB precache + up to ~14 MB glyph runtime cache. Refs #27, #28. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
DocGerd
commented
Jul 16, 2026
DocGerd
commented
Jul 16, 2026
DocGerd
commented
Jul 16, 2026
DocGerd
commented
Jul 16, 2026
DocGerd
commented
Jul 16, 2026
DocGerd
commented
Jul 16, 2026
DocGerd
commented
Jul 16, 2026
DocGerd
commented
Jul 16, 2026
DocGerd
commented
Jul 16, 2026
Owner
Author
|
Out-of-diff self-review findings (docs the PR forgot), accepted for the fix wave:
|
…ps, fix stale numbers Lens round on PR #41 (code / silent-failure / comment-accuracy): - glyphWarmup: console.warn on every unusable-manifest path (non-ok, malformed, thrown) and in scheduleGlyphWarmup's catch-all — warn, not error, so the offline e2e's error collector stays meaningful; the warm-up is a degraded-but-working state, never a silent one. Tests pin the warns. - vite.config glyphManifest(): an empty/missing fonts directory now fails the build (this.error) — deploy is build-gated only, so a fontless offline experience must not ship silently. - Dev-mode skip misattribution fixed in glyphs.ts, vite.config.ts, main.tsx and the warm-up outcome doc/test title: in dev the warm-up parks forever in whenControlled() (no SW ever registers); the manifest-404 path only runs under a stale controlling SW. - Numbers re-measured: glyph cache is ~11 MB (was written as ~14 MB) in glyphs.ts, sw.ts, main.tsx, vite.config.ts; precache "~30 MB" -> "~33 MB"; BATCH_SIZE size claim corrected (avg ~14 KB, CJK-heavy tail > 50 KB); "install/activate must stay instant" -> "must not grow" (install awaits the ~33 MB precache). - swRecovery: dangling "issue's never list" pointer fixed; accepted-cost comment added (reload discards planner form state / in-flight compute; IndexedDB plans safe; fires once per session on a visibly broken page). - glyphs.ts version-bump checklist now names the offline.spec.ts cache-name literal explicitly. - README "First load / offline": ~33 MB precache + ~11 MB background font runtime cache (#28), ~45 MB total eventual download. - CLAUDE.md PWA section: glyph runtime-cache bullet incl. the never-extend-install invariant and bump-procedure pointer. Refs #27, #28. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes the two service-worker robustness issues from the live v0.1.0 verification: the first-install budget blowout (#28) and the pre-SW basemap failure window (#27).
Closes #27
Closes #28
What changed
#28 — install shrinks from 791 entries / ~44 MB to 24 entries / ~33 MB. It turned out 768 of the 791 precache entries were font glyph-range
.pbffiles (the issue estimated ~500). They move to a runtime CacheFirst route (sailcommand-glyphs-v1), scoped to same-origin/basemap-assets/fonts/**.pbfonly — the Open-Meteo origin can never match (unit-pinned). A build-emittedglyph-manifest.json(768 sorted paths) drives a window-side background warm-up: after the SW takes control, at browser idle, missing ranges are fetched in polite batches of 8 (bails offline, non-fatal on failure, resumes next visit) so full offline coverage converges without blocking install. Retired glyph caches (sailcommand-glyphs-*≠ current) are deleted on activate — no leaked megabytes on future version bumps.#27 — one-shot recovery. MapLibre errors that occur while the page is not yet SW-controlled (the window where GitHub Pages' gzip-stamped Range responses break tiles) are recorded; on the first
controllerchangethe page reloads exactly once (sessionStorage guard written before the reload — loop-proof; never armed when already controlled at load).Invariants preserved (the hard rules)
.pmtilesRange→206 route stays literally the first registration — verified in the builtdist/sw.jsin both review rounds.clients.claim().registerType: 'prompt'); stale font precache entries are pruned on activation; worst case is a one-time re-fetch of rendered glyphs.Honest offline testing, strengthened
The server-kill offline spec now waits on deterministic signals before killing (warm-up terminal state + runtime cache ≥ 768 manifest entries — a dead warm-up cannot pass), probes a glyph range offline (must be a 200 from cache against a dead server), and asserts zero console errors across the whole offline phase. The fixture-less built-output guards additionally assert: no font entries in the precache manifest, entry count < 400, and glyph-manifest ↔ dist cross-checks in both directions.
Verification
realmask.repro.done, 768 glyph cache entries, no Open-Meteo cache, 0 console errors, labels rendering.🤖 Generated with Claude Code