Skip to content

PWA SW: non-home navigations show offline.html on a network blip (trailing-slash cache-miss amplifier) #317

Description

@TortoiseWolfe

Symptom

On a transient network blip to scripthammer.com, navigating to any non-home page (e.g. `/blog`) shows the PWA "You're Offline" page, while the homepage keeps working and other sites are fine. Reported 2026-07-18; self-resolves when the network recovers.

Root cause (diagnosed — a latent bug, not a recent regression)

`public/sw.js`'s navigate handler is network-first: it serves `offline.html` only when the navigation `fetch()` rejects and the cache then misses. Two things combine:

  1. Trigger (environmental): a transient network failure reaching scripthammer.com. Not IPv6 — the domain has only A records (185.199.108-111.153), no AAAA. Server is healthy (`/blog/` → 200; `/blog` → 301 → `/blog/`).
  2. Amplifier (the real bug): the install precache stores `./blog/` (WITH trailing slash), but users navigate to `/blog` (no slash). On the `.catch()` fallback, `caches.match('/blog')` misses the `/blog/` entry, so instead of serving the cached blog page it drops to `offline.html`. The homepage survives a blip because `./` is precached and matches.

The navigate handler + precache have been unchanged since 2026-03-10 (`e04650f`).

Verified deterministically by running the real `public/sw.js` fetch handler in Node against a mocked cache/network: offline + `/blog` → offline.html; offline + `/blog/` → cached; online + `/blog` → network.

Proposed fix

In the navigate `.catch()` fallback, make the cache lookup robust before falling to `offline.html`:

  • try the request URL as-is, then with the trailing slash toggled, and with `{ ignoreSearch: true }`;
  • serve `offline.html` only when all variants miss (preserving true-offline correctness for genuinely-uncached routes).

Secondary cleanups worth folding in:

  • `CACHE_VERSION` is hard-coded `scripthammer-v1.0.0` and never bumps on deploy → returning visitors keep a frozen precache.
  • `public/service-worker.js` is dead/unregistered code (the registered SW is `/sw.js`).

Constraints

  • Preserve scope-relative paths (basePath forks like `/RepoName/`).
  • Static multi-page export: each route is its own HTML, so the fix is cache-tolerance, not a single app-shell.
  • Also applies to the RescueDogs fork (kept the PWA) — add to RescueDogs#56 when fixed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions