pwa / offline mode
- @vite-pwa/sveltekit: workbox precache (incl. pdfjs worker), generated manifest, prompt-style updates via PwaUpdatePrompt toast - prerendered routes for offline navigation, PWA icons, theme-color + apple-touch-icon - pwa offline/update e2e suite (pnpm test:pwa, playwright.pwa.config.ts) - datenschutz: offline/install section; prettier cleanup of shadcn components
This commit is contained in:
1 parent
b7969b4c9e
commit
f09384d2e6
37 files changed
+4130
-273
No files matched your search
@@ -0,0 +1,146 @@
|
||||
# Plan: PWA / Offline-Fähigkeit
|
||||
|
||||
## Goal
|
||||
|
||||
The app already processes everything locally — but the browser still has to fetch the app shell
|
||||
from the server on every load. Making **beA-Edit an installable, offline-capable PWA** reinforces
|
||||
the privacy story ("works without internet after first load"), enables home-screen/desktop
|
||||
installation, and is essentially free given there are no network calls to cache-around.
|
||||
|
||||
---
|
||||
|
||||
## Open decisions (defaults marked ✅)
|
||||
|
||||
### D1 — Implementation approach
|
||||
|
||||
- ✅ **A. `@vite-pwa/sveltekit`** (new **dev** dependency). Mature integration: precaching of the
|
||||
built assets via Workbox, generated manifest, virtual `RegisterSW` module, works with
|
||||
`adapter-node` builds. The dependency is justified (agents.md allows deps when the task cannot
|
||||
reasonably be done without) — hand-rolling a correct service worker + update flow is
|
||||
error-prone.
|
||||
- B. Hand-written minimal `sw.js` in `static/` + manual manifest. Zero deps but custom update
|
||||
logic, manual asset hashing, more long-term maintenance.
|
||||
|
||||
### D2 — Update UX
|
||||
|
||||
- ✅ **A. Auto-update with a toast.** New versions activate on next navigation; a small toast
|
||||
"Neue Version verfügbar – Seite neu laden" appears when an update is waiting (Workbox
|
||||
`onNeedRefresh`/`onOfflineReady` hooks). Never force-reload mid-work (users may have unsaved
|
||||
archive state).
|
||||
- B. Silent auto-reload. Rejected: could interrupt an in-progress merge.
|
||||
|
||||
### D3 — Legal pages
|
||||
|
||||
- ✅ **Review required, not auto-edited.** A service worker + install prompt is client-side
|
||||
storage/behavior; `datenschutz/+page.svelte` should likely gain a sentence. Flag for the user;
|
||||
do not rewrite legal copy unilaterally (project constraint).
|
||||
|
||||
---
|
||||
|
||||
## Technical approach
|
||||
|
||||
### Vite config
|
||||
|
||||
```ts
|
||||
// vite.config.ts
|
||||
import { SvelteKitPWA } from '@vite-pwa/sveltekit';
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
sveltekit(),
|
||||
tailwindcss(),
|
||||
SvelteKitPWA({
|
||||
registerType: 'prompt',
|
||||
manifest: {
|
||||
name: 'beA-Edit',
|
||||
short_name: 'beA-Edit',
|
||||
description: 'PDF-Werkzeuge für die beA-Kanzlei – 100 % lokal im Browser.',
|
||||
lang: 'de',
|
||||
start_url: '/',
|
||||
display: 'standalone',
|
||||
background_color: '#f2f5f8', // align with theme background token
|
||||
theme_color: '#…', // align with primary token
|
||||
icons: [
|
||||
/* 192 + 512 + maskable, derived from static logo */
|
||||
]
|
||||
},
|
||||
workbox: {
|
||||
globPatterns: ['**/*.{js,css,html,svg,woff2}'],
|
||||
navigateFallback: '/' // SPA-style offline fallback for app routes
|
||||
},
|
||||
devOptions: { enabled: false }
|
||||
})
|
||||
]
|
||||
});
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
- pdfjs worker chunk (`pdf.worker.mjs?url`) is part of the built assets → precached by glob.
|
||||
- Legal routes (`/impressum`, `/datenschutz`) precache like any route; offline navigation works
|
||||
via the fallback.
|
||||
- No runtime caching strategies needed: the app makes **no** network requests by design.
|
||||
|
||||
### Registration UI
|
||||
|
||||
- Root `+layout.svelte`: import the virtual `virtual:pwa-register` module (SSR-guarded), wire
|
||||
`onNeedRefresh` → toast state; render a small dismissible toast component (build with existing
|
||||
card/button styling; no new UI dep) with "Neu laden" / "Später".
|
||||
- `onOfflineReady` → optional one-time hint "beA-Edit funktioniert jetzt offline." (keep subtle).
|
||||
- Install prompt: rely on the browser's native install affordance (manifest makes it appear);
|
||||
optionally an "Installieren" hint on the start page later — out of scope for v1.
|
||||
|
||||
### Icons
|
||||
|
||||
- Generate 192/512/maskable PNGs from the existing logo (`static/` logo asset) once, committed
|
||||
to `static/icons/`. Use an offline tool/imagemagick during implementation; no runtime dep.
|
||||
|
||||
### Docker / adapter-node
|
||||
|
||||
- Service worker + manifest are static build output → served by `node build/index.js` without
|
||||
changes. Verify `Cache-Control` headers don't block SW updates (adapter-node defaults are fine;
|
||||
the SW itself must not be cached aggressively — Vite PWA emits the right filenames).
|
||||
|
||||
## Files changed
|
||||
|
||||
- `vite.config.ts` — SvelteKitPWA plugin + manifest.
|
||||
- `package.json` / lockfile — `@vite-pwa/sveltekit` dev dependency (via pnpm only).
|
||||
- `src/routes/+layout.svelte` — registration + update toast.
|
||||
- `static/icons/*` — generated icons; `static/manifest.webmanifest` handled by plugin.
|
||||
- `src/app.html` — `theme-color` meta if plugin doesn't inject.
|
||||
- `agents.md` — document PWA setup + update behavior.
|
||||
- `datenschutz/+page.svelte` — only after explicit user approval (D3).
|
||||
|
||||
## Implementation phases
|
||||
|
||||
1. Add dependency, configure plugin + manifest + icons.
|
||||
2. Registration + update toast in root layout.
|
||||
3. Build + `pnpm preview`: verify `/` loads, then devtools → Application → service worker
|
||||
registered; toggle "Offline" → reload → app still works.
|
||||
4. Production image smoke test (Docker build, offline reload).
|
||||
5. Update `agents.md`; flag datenschutz review.
|
||||
|
||||
## Verification
|
||||
|
||||
- Fresh load registers the SW (devtools), `onOfflineReady` path reachable.
|
||||
- Offline reload after precache: start page + all tool routes render; dropping a ZIP still works
|
||||
fully (entire processing chain offline).
|
||||
- New build deployed → toast offers reload; choosing it loads the new version; declining does
|
||||
not interrupt current state.
|
||||
- No console errors on iOS Safari (manifest parsing quirks) — best-effort check.
|
||||
- `pnpm check`, `pnpm lint`, `pnpm build` pass.
|
||||
|
||||
## Risks
|
||||
|
||||
- **Stale cache confusion** during development: keep `devOptions.enabled: false`; document in
|
||||
agents.md that preview/production test the SW, not dev mode.
|
||||
- **Large precache manifest**: the pdfjs worker + fonts add a few MB to the first precache —
|
||||
acceptable for an installable tool; monitor build output stats.
|
||||
- **SW + SvelteKit hydration edge cases** on first offline visit are known upstream; pin a
|
||||
current stable plugin version and test the exact offline-reload sequence.
|
||||
|
||||
## Out of scope
|
||||
|
||||
- Background sync (nothing to sync — no network by design).
|
||||
- App-store packaging.
|
||||
- Custom install button UI beyond the native affordance.
|
||||
Reference in new issue
Block a user