[BUGFIX] PWA service worker update handling - #453
Open
maurerle wants to merge 4 commits into
Open
Conversation
registerType defaulted to "prompt", which emits a worker that only calls skipWaiting() on a SKIP_WAITING message, and nothing in the app ever sent one. Every deployment installed a new worker that then sat in "waiting" indefinitely, so users kept being served the previous precache until they closed every tab of the origin. Switching to "autoUpdate" alone is not enough: with injectRegister "auto" and no virtual:pwa-register import, only a bare register() call is emitted and the already rendered page is never reloaded, delaying the update by one reload. Importing registerSW pulls in the register template that reloads on activation. This requires the plugin to stay loaded even for the PR preview build, hence disable: instead of dropping it from the plugin list. Measured against a real build with a scripted deployment (13.2.0 -> 13.2.1) in headless Chromium: before, the new bundle appeared only after closing all tabs; with autoUpdate alone on the second reload; with the import on the first. devOptions is switched off because autoUpdate would hard-reload the dev server on every worker regeneration, discarding HMR state. Assisted by (claude-5): Claude Opus 5
navigateFallbackDenylist was written as new RegExp(".*\.json"), where the
escape is dropped by the string literal, yielding an unanchored /.*.json/.
More importantly it covered only JSON, so every other non-precached path hit
the index.html fallback. sw.js is the one asset a worker never precaches, so
navigating to /sw.js returned the full application as text/html.
Denying anything that ends in a file extension fixes that while leaving the
SPA fallback intact for extension-less routes. Workbox matches the denylist
against pathname + search, so the pattern allows a trailing query and keeps
covering URLs like /config.json?v=2, which the old unanchored pattern did.
Assisted by (claude-5): Claude Opus 5
offline.html dates back to the 2018 network-only worker, which fetched every request and fell back to that page on failure. The Vite migration replaced that strategy with Workbox precaching, and nothing has referenced the page since: it was built as an entry point and precached, but no navigateFallback, no catch handler and no link pointed at it, so it could never be reached. Precaching also introduced the gap it was meant to cover. Offline the shell now loads from the precache and only config.json fails, and because fetch rejects rather than returning a non-ok response, that rejection went unhandled and the loading text stayed on screen forever. Verified in headless Chromium with the network disabled: before, the page kept showing "Lade Karten & Knoten..." and logged "Failed to fetch"; now it shows "No connection available." with the existing reload button and no unhandled error. Assisted by (claude-5): Claude Opus 5
The image ran on the stock nginx config, which sends no Cache-Control at all, leaving browsers to cache the entry points heuristically from Last-Modified. That works against the service worker update path: a stale index.html or sw.js delays the update the previous commits enable. Revalidate everything by default and cache only assets/ aggressively, which is safe because Vite puts a content hash in those filenames. Assisted by (claude-5): Claude Opus 5
Contributor
|
Preview deployed: https://freifunk.github.io/meshviewer/pr-preview/pr-453/ Updated for commit 8e705db. |
maurerle
force-pushed
the
fix/pwa-service-worker-updates
branch
from
August 13, 2026 07:58
870f489 to
8e705db
Compare
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.
Description
This PR resolves several lingering issues with the PWA and service worker implementation following the Vite migration, primarily ensuring that users receive app updates reliably and experience correct offline behaviors.
The four fixes include:
will automatically update and reload when a new version is activated.
served correctly.
app shell now gracefully displays a "No connection available" message instead of hanging on the loading screen.
stale caches from blocking app updates, while hashed assets/ are cached aggressively for performance.
Motivation and Context
The service worker was not updating correctly after deploying the new version and did show the old version after deployment of a new version on the server.
Furthermore links like https://map.aachen.freifunk.net/sw.js do show a map loaded from the service worker instead of the service worker js - if the PWA is cached. This should not be the case.
How Has This Been Tested?
connection available." UI, whereas previously it would hang indefinitely on the loading screen and log unhandled Failed to fetch errors.
bundle now appears on the very first page reload. Previously, the new bundle would only appear if all tabs to the origin were completely closed.
Screenshots/links:
Checklist: