[Frontend] PWA scaffolding: manifest, service worker, icons #108

Closed
opened 2026-07-14 19:50:10 +00:00 by claude-bot · 1 comment
Contributor

Context

webapp/frontend/index.html is bare — a title and viewport meta only: no web manifest, no service worker, no theme-color, no icons. The app is neither installable nor offline-tolerant. Additionally, the theme default is hard-coded to "dark" on first visit (src/hooks/useTheme.jsx:10-11localStorage.getItem("qb_theme") ?? "dark"), ignoring prefers-color-scheme.

Motivation

Players use this on phones at the table. Installable + a sane offline fallback is table-stakes mobile polish, and the manifest/theme-color work also fixes the jarring white/dark flash mismatch for light-theme users.

Fix / Spec

  1. Add vite-plugin-pwa with:
    • Web manifest: name "Quest Board", short_name, display standalone, theme/background colors, maskable icons + apple-touch icon. Generate simple placeholder iconography if no asset exists and note in the PR where to swap real art.
    • theme-color meta in index.html.
  2. Service worker caching strategy:
    • Cache-first for hashed static assets (JS/CSS/fonts — safe because filenames are content-hashed).
    • Network-first with a short timeout and no long-lived cache for /api/* — authenticated JSON must never be served stale-offline as if fresh.
    • A minimal offline fallback page for navigation requests when the network is down. No offline data features in this issue.
  3. First-visit theme: honor prefers-color-scheme when no stored preference exists (useTheme.jsx:10-11), keeping the stored qb_theme override behavior intact.
  4. Ensure the service worker plays nicely with route-level code splitting (lazy chunks precached or fetched cache-first).

Acceptance criteria

  • Lighthouse reports the app installable (manifest + SW + icons all pass).
  • Hard refresh while offline shows the fallback page, not a browser error.
  • Login and live data behave normally online; no API response is ever served from SW cache as fresh.
  • First visit with OS light mode → light theme; toggling and revisiting persists the choice.
  • SW updates activate on new deploys without users being stuck on stale bundles (skipWaiting/clientsClaim or an update prompt — decide and note).

References

  • webapp/frontend/index.html
  • webapp/frontend/src/hooks/useTheme.jsx:10-11
  • webapp/frontend/vite.config.js

Filed from the July 2026 full-project review.

## Context `webapp/frontend/index.html` is bare — a title and viewport meta only: no web manifest, no service worker, no `theme-color`, no icons. The app is neither installable nor offline-tolerant. Additionally, the theme default is hard-coded to `"dark"` on first visit (`src/hooks/useTheme.jsx:10-11` — `localStorage.getItem("qb_theme") ?? "dark"`), ignoring `prefers-color-scheme`. ## Motivation Players use this on phones at the table. Installable + a sane offline fallback is table-stakes mobile polish, and the manifest/theme-color work also fixes the jarring white/dark flash mismatch for light-theme users. ## Fix / Spec 1. Add `vite-plugin-pwa` with: - Web manifest: name "Quest Board", short_name, display standalone, theme/background colors, **maskable** icons + apple-touch icon. Generate simple placeholder iconography if no asset exists and note in the PR where to swap real art. - `theme-color` meta in `index.html`. 2. Service worker caching strategy: - **Cache-first** for hashed static assets (JS/CSS/fonts — safe because filenames are content-hashed). - **Network-first with a short timeout and no long-lived cache** for `/api/*` — authenticated JSON must never be served stale-offline as if fresh. - A minimal offline fallback page for navigation requests when the network is down. No offline data features in this issue. 3. First-visit theme: honor `prefers-color-scheme` when no stored preference exists (`useTheme.jsx:10-11`), keeping the stored `qb_theme` override behavior intact. 4. Ensure the service worker plays nicely with route-level code splitting (lazy chunks precached or fetched cache-first). ## Acceptance criteria - [ ] Lighthouse reports the app installable (manifest + SW + icons all pass). - [ ] Hard refresh while offline shows the fallback page, not a browser error. - [ ] Login and live data behave normally online; no API response is ever served from SW cache as fresh. - [ ] First visit with OS light mode → light theme; toggling and revisiting persists the choice. - [ ] SW updates activate on new deploys without users being stuck on stale bundles (skipWaiting/clientsClaim or an update prompt — decide and note). ## References - `webapp/frontend/index.html` - `webapp/frontend/src/hooks/useTheme.jsx:10-11` - `webapp/frontend/vite.config.js` _Filed from the July 2026 full-project review._
Author
Contributor

Note for whoever does the manual verification pass — this issue's first acceptance criterion can no longer be satisfied as written.

  • Lighthouse reports the app installable (manifest + SW + icons all pass).

Lighthouse removed the PWA category in v12 (2024). There is no "Progressive Web App" audit in the DevTools Lighthouse panel any more, so there's no Lighthouse report that says "installable". The checks it used to run were folded into DevTools → Application.

The equivalent verification today, against https://questboard-dev.rhoving.com (now deployed from main):

Was Now
Lighthouse → PWA → "Installable" Application → Manifest → Installability (no errors) + the install icon in the address bar
Lighthouse → PWA → SW registered Application → Service Workersactivated and is running
Lighthouse → PWA → icons Application → Manifest → icons render, incl. the maskable one

Two setup notes that will otherwise produce false failures:

  1. Service workers require a secure context. https://questboard-dev.rhoving.com works; hitting the dev host directly over plain HTTP (http://10.1.1.14:18081) will silently not register the SW, making a working PWA look broken.
  2. Emulate the OS theme in DevTools (Rendering → Emulate CSS prefers-color-scheme) rather than changing your OS, and clear qb_theme from Local Storage (or use Incognito) to exercise the genuine first-visit path.

What was verified automatically, since it doesn't need a browser: the manifest is served as application/manifest+json (nginx has no .webmanifest MIME entry by default — fixed in this PR), the served index.html has zero inline scripts so nothing is blocked by the script-src 'self' CSP, sw.js/registerSW.js/theme-init.js/icons all return 200 through the real HTTPS origin, and the generated sw.js contains 0 precache entries referencing /api with both NetworkOnly rules intact.

What still genuinely needs a human: confirming the install prompt actually appears, and that a hard refresh while offline renders the shell rather than the browser's offline page.

Note for whoever does the manual verification pass — **this issue's first acceptance criterion can no longer be satisfied as written**. > - [ ] Lighthouse reports the app installable (manifest + SW + icons all pass). **Lighthouse removed the PWA category in v12 (2024).** There is no "Progressive Web App" audit in the DevTools Lighthouse panel any more, so there's no Lighthouse report that says "installable". The checks it used to run were folded into **DevTools → Application**. The equivalent verification today, against `https://questboard-dev.rhoving.com` (now deployed from `main`): | Was | Now | |---|---| | Lighthouse → PWA → "Installable" | **Application → Manifest → Installability** (no errors) + the **install icon in the address bar** | | Lighthouse → PWA → SW registered | **Application → Service Workers** → *activated and is running* | | Lighthouse → PWA → icons | **Application → Manifest** → icons render, incl. the maskable one | Two setup notes that will otherwise produce false failures: 1. **Service workers require a secure context.** `https://questboard-dev.rhoving.com` works; hitting the dev host directly over plain HTTP (`http://10.1.1.14:18081`) will silently *not* register the SW, making a working PWA look broken. 2. **Emulate the OS theme in DevTools** (Rendering → *Emulate CSS `prefers-color-scheme`*) rather than changing your OS, and clear `qb_theme` from Local Storage (or use Incognito) to exercise the genuine first-visit path. What was verified automatically, since it doesn't need a browser: the manifest is served as `application/manifest+json` (nginx has no `.webmanifest` MIME entry by default — fixed in this PR), the served `index.html` has **zero inline scripts** so nothing is blocked by the `script-src 'self'` CSP, `sw.js`/`registerSW.js`/`theme-init.js`/icons all return 200 through the real HTTPS origin, and the generated `sw.js` contains **0** precache entries referencing `/api` with both `NetworkOnly` rules intact. What still genuinely needs a human: confirming the **install prompt actually appears**, and that a **hard refresh while offline** renders the shell rather than the browser's offline page.
rbrooks referenced this issue from a commit 2026-07-17 15:23:55 +00:00
Sign in to join this conversation.
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
rbrooks/Quest-Board#108
No description provided.