feat(pwa): installierbar + Offline-Grundgeruest
- Manifest (name/standalone/theme-color wald), Icons aus echtem Logo (192/512/maskable/apple-touch) via scripts/generate-pwa-icons.mjs - app.html: manifest + theme-color + apple-touch-icon + iOS-Meta - service-worker.ts: precache Build-Assets, Seiten network-first mit Offline-Cache-Fallback (SvelteKit registriert autom. in Prod) - Push (VAPID) folgt separat Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
/// <reference types="@sveltejs/kit" />
|
||||
/// <reference no-default-lib="true"/>
|
||||
/// <reference lib="esnext" />
|
||||
/// <reference lib="webworker" />
|
||||
import { build, files, version } from "$service-worker";
|
||||
|
||||
const sw = self as unknown as ServiceWorkerGlobalScope;
|
||||
|
||||
const CACHE = `ww-cache-${version}`;
|
||||
// Vom Build erzeugte Assets + statische Dateien (Icons, Manifest, Fonts…).
|
||||
const PRECACHE = [...build, ...files];
|
||||
|
||||
sw.addEventListener("install", (event) => {
|
||||
event.waitUntil(
|
||||
caches
|
||||
.open(CACHE)
|
||||
.then((cache) => cache.addAll(PRECACHE))
|
||||
.then(() => sw.skipWaiting()),
|
||||
);
|
||||
});
|
||||
|
||||
sw.addEventListener("activate", (event) => {
|
||||
event.waitUntil(
|
||||
(async () => {
|
||||
for (const key of await caches.keys()) {
|
||||
if (key !== CACHE) await caches.delete(key);
|
||||
}
|
||||
await sw.clients.claim();
|
||||
})(),
|
||||
);
|
||||
});
|
||||
|
||||
sw.addEventListener("fetch", (event) => {
|
||||
const req = event.request;
|
||||
if (req.method !== "GET") return;
|
||||
|
||||
const url = new URL(req.url);
|
||||
// Nur same-origin — CMS-/Cross-Origin-Requests (dynamischer Content) nicht cachen.
|
||||
if (url.origin !== sw.location.origin) return;
|
||||
|
||||
// Precache-Assets → cache-first (unveränderlich pro Version).
|
||||
if (PRECACHE.includes(url.pathname)) {
|
||||
event.respondWith(caches.match(req).then((r) => r ?? fetch(req)));
|
||||
return;
|
||||
}
|
||||
|
||||
// Seiten → network-first, bei Offline aus Cache; sonst Hinweis.
|
||||
if (req.mode === "navigate") {
|
||||
event.respondWith(
|
||||
(async () => {
|
||||
try {
|
||||
const res = await fetch(req);
|
||||
const cache = await caches.open(CACHE);
|
||||
cache.put(req, res.clone());
|
||||
return res;
|
||||
} catch {
|
||||
const cached = await caches.match(req);
|
||||
return (
|
||||
cached ??
|
||||
new Response("Du bist offline. Diese Seite wurde noch nicht geladen.", {
|
||||
status: 503,
|
||||
headers: { "Content-Type": "text/plain; charset=utf-8" },
|
||||
})
|
||||
);
|
||||
}
|
||||
})(),
|
||||
);
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user