PWA-Installierbarkeit: Seite kann jetzt als App installiert werden (Desktop-Icon)

Recherche (developer.chrome.com, Lighthouse-Doku, Stand 2026): Chrome/Edge
zeigen "App installieren" bei gültigem Web App Manifest (name, icons inkl.
512x512, start_url, display:standalone) UND einem registrierten Service
Worker mit fetch()-Handler — reines Manifest reicht für den zuverlässigen
Install-Prompt nicht mehr aus.

- Neues manifest.json (Name, Theme-/Hintergrundfarbe passend zum dunklen
  Design, Icons 192x192 + 512x512 aus dem bestehenden Husky-Favicon erzeugt)
- Neuer sw.js: minimaler Service Worker, primär für die Installierbarkeit,
  cached nebenbei die wichtigsten Shell-Dateien (Network-first mit
  Cache-Fallback, kein Offline-Vollausbau)
- main.js: registriert den Service Worker nur bei http(s) (nie bei
  file://, damit die Seite laut Projektregel weiterhin per Doppelklick
  ohne Server funktioniert — stiller Fallback statt Konsolenfehler)
- Alle 28 HTML-Seiten: <link rel="manifest"> + <meta name="theme-color">
  im <head> ergänzt (identischer Ankerpunkt nach dem Favicon-Link geprüft
  und automatisiert eingefügt)

Installation für Dogi: Seite in Chrome/Edge öffnen → Symbol rechts in der
Adressleiste ("App installieren") oder Menü ⋮ → "DogFather Universe
installieren" → landet als eigenes Fenster + Icon auf Desktop/Startmenü.
This commit is contained in:
2026-08-03 01:50:56 +02:00
parent c4be588f05
commit c940538b1d
33 changed files with 172 additions and 0 deletions
+71
View File
@@ -0,0 +1,71 @@
/* =====================================================================
sw.js — minimaler Service Worker für DOGFATHER UNIVERSE
Zweck: NICHT primär Offline-Funktionalität, sondern die technische
Voraussetzung, damit Chrome/Edge auf dem Desktop den "App installieren"-
Prompt zuverlässig anzeigt (Chrome verlangt dafür einen registrierten
Service Worker mit fetch()-Handler, siehe developer.chrome.com/blog/
update-install-criteria, Stand 2026). Nebenbei cached er die wichtigsten
Shell-Dateien, damit die Seite bei Verbindungsabbruch nicht komplett
leer bleibt — bewusst simpel gehalten (kein Offline-Vollausbau).
===================================================================== */
const CACHE_NAME = "dogfather-universe-shell-v1";
const SHELL_ASSETS = [
"/",
"/index.html",
"/assets/css/main.css",
"/assets/css/theme-dogfather.css",
"/assets/css/theme-hasidog.css",
"/assets/css/theme-spicymedia.css",
"/assets/js/main.js",
"/assets/img/favicon.png",
"/assets/img/icon-192.png",
"/assets/img/icon-512.png",
];
self.addEventListener("install", (event) => {
event.waitUntil(
caches
.open(CACHE_NAME)
.then((cache) => cache.addAll(SHELL_ASSETS))
.catch(() => {
/* Einzelne Assets könnten fehlen (z.B. beim allerersten Deploy) —
soll die Installation des Service Workers nicht blockieren. */
})
);
self.skipWaiting();
});
self.addEventListener("activate", (event) => {
event.waitUntil(
caches
.keys()
.then((keys) =>
Promise.all(
keys
.filter((key) => key !== CACHE_NAME)
.map((key) => caches.delete(key))
)
)
.then(() => self.clients.claim())
);
});
/* Network-first mit Cache-Fallback: liefert immer die aktuellste Version,
greift nur bei echtem Verbindungsausfall auf den Cache zurück — damit
Änderungen an der Seite nicht durch veraltete Caches verdeckt werden. */
self.addEventListener("fetch", (event) => {
if (event.request.method !== "GET") return;
const url = new URL(event.request.url);
if (url.origin !== self.location.origin) return;
event.respondWith(
fetch(event.request)
.then((response) => {
const copy = response.clone();
caches.open(CACHE_NAME).then((cache) => cache.put(event.request, copy));
return response;
})
.catch(() => caches.match(event.request))
);
});