- @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
5.9 KiB
5.9 KiB
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, virtualRegisterSWmodule, works withadapter-nodebuilds. 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.jsinstatic/+ 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/onOfflineReadyhooks). 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.svelteshould likely gain a sentence. Flag for the user; do not rewrite legal copy unilaterally (project constraint).
Technical approach
Vite config
// 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 virtualvirtual:pwa-registermodule (SSR-guarded), wireonNeedRefresh→ 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 tostatic/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.jswithout changes. VerifyCache-Controlheaders 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/sveltekitdev dependency (via pnpm only).src/routes/+layout.svelte— registration + update toast.static/icons/*— generated icons;static/manifest.webmanifesthandled by plugin.src/app.html—theme-colormeta if plugin doesn't inject.agents.md— document PWA setup + update behavior.datenschutz/+page.svelte— only after explicit user approval (D3).
Implementation phases
- Add dependency, configure plugin + manifest + icons.
- Registration + update toast in root layout.
- Build +
pnpm preview: verify/loads, then devtools → Application → service worker registered; toggle "Offline" → reload → app still works. - Production image smoke test (Docker build, offline reload).
- Update
agents.md; flag datenschutz review.
Verification
- Fresh load registers the SW (devtools),
onOfflineReadypath 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 buildpass.
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.