Servicemitarbeiter: Der programmierbare Netzwerk-Proxy
Verwandeln Sie Ihre Website in eine offlinefähige Anwendung. Ein technischer Leitfaden zum Service Worker-Lebenszyklus, zu Caching-Strategien (Workbox) und zur Hintergrundsynchronisierung.
Der größte Unterschied zwischen einer nativen App und einer Web-App ist Ausfallsicherheit. Wenn Sie Instagram im Flugzeugmodus öffnen, werden zwischengespeicherte Fotos angezeigt. Wenn Sie eine Standard-Website im Flugzeugmodus öffnen, sehen Sie den Dinosaurier.
Dies ist für moderne Software nicht akzeptabel. Servicemitarbeiter sind die Lösung. Dabei handelt es sich um ein JavaScript-Worker-Skript, das unabhängig von einer Webseite im Hintergrund ausgeführt wird. Sie fungieren als Client-seitiger Netzwerk-Proxy.
Bei Maison Code Paris erstellen wir Progressive Web Apps (PWAs), die den „Subway Test“ bestehen: Kann der Benutzer den Katalog unter der Erde durchsuchen? Wenn die Antwort „Nein“ lautet, ist die App defekt.
Warum Maison Code darüber spricht
Bei Maison Code Paris fungieren wir als das architektonische Gewissen unserer Kunden. Wir übernehmen oft „moderne“ Stacks, die ohne grundlegendes Verständnis für Skalierung gebaut wurden.
Wir diskutieren dieses Thema, weil es einen kritischen Wendepunkt in der technischen Reife darstellt. Die korrekte Implementierung unterscheidet ein fragiles MVP von einer widerstandsfähigen Plattform auf Unternehmensniveau.
Warum Maison Code Offline-First verlangt
Ein weißer Bildschirm ist ein verlorener Kunde. Wir behandeln „Offline“ als Funktion und nicht als Fehlerstatus. Unser PWA-Standard gewährleistet:
- Ausfallsicherheit: Die App-Shell wird sofort geladen, sogar bei 2G.
- Engagement: Benutzer können offline etwas in den Warenkorb legen (Background Sync sendet es später).
- Retention: Push-Benachrichtigungen führen bei unseren Mobile-First-Kunden zu einer dreimal höheren Rücklaufquote als E-Mails. Wir erstellen keine „Websites“; Wir bauen „Installable Web Apps“.
Das mentale Modell: Der Mann in der Mitte
Normalerweise: „Browser -> Netzwerk -> Server“.
Mit SW: Browser -> Service Worker.
Der Servicemitarbeiter entscheidet dann:
- „Ich habe das im Cache. Cache zurückgeben.“ (0 ms Latenz).
- „Ich muss zum Netzwerk gehen.“ (Standardlatenz).
- „Gehen Sie zum Netzwerk, aber wenn es fehlschlägt, kehren Sie zum Cache zurück.“ (Elastizität).
Diese Logik ist programmierbar. Sie kontrollieren jedes Byte.
Der Lebenszyklus (der schwierige Teil)
Servicemitarbeiter sind bekanntermaßen schwer zu debuggen, da sie unabhängig vom Tab leben.
- Installieren: Browser lädt „sw.js“ herunter. Es lädt kritische Assets herunter (Precache).
- Aktivieren: Die SW startet. Es bereinigt alte Caches. Entscheidend ist, dass geöffnete Tabs noch nicht gesteuert werden.
- Anspruch: Sie müssen „clients.claim()“ aufrufen, um sofort die Kontrolle über geöffnete Tabs zu übernehmen.
- Fetch: Die SW erstellt einen „Fetch“-Ereignis-Listener.
Das Problem der „neuen Version“.
Sie stellen „v2“ bereit. Benutzer besucht Website. Der Browser sieht, dass „sw.js“ geändert wurde. Es installiert „v2“ im Hintergrund. Aber „v1“ führt die Seite immer noch aus! „v2“ wechselt in den Status „Warten“. Es wird nur aktiviert, wenn alle Tabs geschlossen sind. Um dies zu beheben, implementieren wir einen „Update verfügbar“-Toast in der Benutzeroberfläche.
„Javascript // In Ihrer React-App if (registration.waiting) { showToast(“Update verfügbar”, () => { Registration.waiting.postMessage({ type: ‘SKIP_WAITING’ }); window.location.reload(); }); } „
Caching-Strategien (mit Workbox)
Das Schreiben der rohen Caching-Logik ist fehleranfällig. Wir verwenden Google Workbox.
1. Precache (Die App Shell)
Während der Installation laden wir das HTML-Gerüst, das Logo und das Haupt-JS-Bundle herunter. Diese Dateien werden im Cache „gepinnt“. Sie sind garantiert da.
„Javascript import { precacheAndRoute } aus ‘workbox-precaching’; // __WB_MANIFEST wird vom Build-Tool (Webpack/Vite) injiziert precacheAndRoute(self.__WB_MANIFEST); „
2. Stale-While-Revalidate (dynamischer Inhalt)
Bei API-Aufrufen („/api/products“) wollen wir Geschwindigkeit, aber auch Aktualität.
- Schritt 1: Zwischengespeichertes JSON sofort zurückgeben. (App rendert in 50 ms).
- Schritt 2: Aktuelles JSON aus dem Netzwerk abrufen.
- Schritt 3: Cache aktualisieren.
- Schritt 4: Aktualisierung an die Benutzeroberfläche übertragen („Neue Preise verfügbar“).
„Javascript import { registerRoute } aus ‘workbox-routing’; import { StaleWhileRevalidate } from ‘workbox-strategies’;
registerRoute( ({ url }) => url.pathname.startsWith(‘/api/’), new StaleWhileRevalidate({ CacheName: ‘api-cache’, Plugins: [ new ExpirationPlugin({ maxEntries: 50, maxAgeSeconds: 3600 }), // 1 Stunde lang aufbewahren ], }) ); „
3. Zuerst zwischenspeichern (unveränderliche Vermögenswerte)
Für Produktbilder (die auf CDNs mit versionierten URLs gehostet werden) verwenden wir Cache First. Wenn es sich im Cache befindet, geben Sie es zurück. Gehen Sie niemals ins Netzwerk.
Offline-Speicher: IndexedDB
„LocalStorage“ ist synchron. Es blockiert den Hauptthread. Servicemitarbeiter sind asynchron. Sie können nicht auf LocalStorage zugreifen. Sie müssen IndexedDB verwenden. Es handelt sich um eine NoSQL-Datenbank im Browser. Wir verwenden es, um „Ausstehende Aktionen“ zu speichern.
Szenario: Der Benutzer klickt offline auf „In den Warenkorb“.
- App erkennt offline.
- App schreibt Aktion in IndexedDB: „{ type: ‚ADD_TO_CART‘, id: 123 }“.
- App aktualisiert optimistisch die Benutzeroberfläche (Badge zeigt „1“).
- Der Servicemitarbeiter registriert ein Hintergrundsynchronisierungsereignis.
Hintergrundsynchronisierung
Das ist die Killerfunktion. Wenn die Verbindung wiederhergestellt wird (auch wenn der Benutzer die App geschlossen hat!), weckt das Betriebssystem den Service Worker.
„Javascript // sw.js self.addEventListener(‘sync’, (event) => { if (event.tag === ‘sync-cart’) { event.waitUntil(syncCart()); } });
asynchrone Funktion syncCart() { const db = wait openDB(‘my-store’); const action = waiting db.get(‘pending’, ‘cart’); wait fetch(‘/api/cart’, { method: ‘POST’, body: JSON.stringify(action) }); } „
Häufige Fallstricke
- Den Service Worker selbst zwischenspeichern: Stellen Sie sicher, dass Ihr Server „Cache-Control: no-cache“ für „sw.js“ sendet. Wenn der Browser die SW-Datei 24 Stunden lang zwischenspeichert, können Sie 24 Stunden lang keine Updates bereitstellen.
- Undurchsichtige Antworten (CORS): Wenn Sie ein Bild von „cdn.shopify.com“ ohne CORS-Header abrufen, sieht die SW eine „Opaque Response“. Der Statuscode kann nicht überprüft werden. Möglicherweise wird eine 404-Fehlerseite als Bild zwischengespeichert. Konfigurieren Sie CORS immer für Ihre Buckets.
- Kontingent überschritten: Browser begrenzen den Speicherplatz (normalerweise 10–20 % des Speicherplatzes). Implementieren Sie immer LRU-Räumungsrichtlinien (Least Recent Used, LRU) (mithilfe des Workbox Expiration Plugins).
10. Regelmäßige Hintergrundsynchronisierung
Die Standardsynchronisierung funktioniert, wenn die Verbindung wiederhergestellt ist.
Periodische Synchronisierung ermöglicht es der App, im Hintergrund aufzuwachen (z. B. alle 24 Stunden), um neue Inhalte abzurufen.
Stellen Sie sich eine Nachrichten-App vor. Sie möchten, dass der Benutzer die morgendlichen Schlagzeilen sieht, bevor er die App öffnet.
registration.periodicSync.register('get-headlines', { minInterval: 24 * 60 * 60 * 1000 });.
Hinweis: Hierfür ist in der Regel die Installation der PWA auf dem Startbildschirm erforderlich.
11. Debugging-Tipps (Chrome DevTools)
Die Registerkarte „Anwendung“ in Chrome ist Ihr bester Freund.
- Update beim Neuladen: Aktivieren Sie dieses Kontrollkästchen während der Entwicklung. Dadurch wird der Browser gezwungen, den SW-Cache für die SW-Datei selbst zu umgehen.
- Registrierung aufheben: Nukleare Option. Wenn die Dinge seltsam sind, heben Sie die Registrierung der SW auf, um neu zu beginnen.
- Cache-Speicher: Sehen Sie sich genau an, welche JSON-Blobs gespeichert werden. Wenn „api-cache“ leer ist, ist Ihr Regex-Matcher falsch.
13. Verschlüsselung der Push-Benachrichtigungsnutzlast
Web Push ist verschlüsselt (AES-128-GCM).
Der Browser generiert ein öffentliches/privates Schlüsselpaar.
Der Server (VAPID) muss die Nutzlast mit dem öffentlichen Schlüssel des Browsers verschlüsseln.
Wenn Sie reines JSON senden, lehnt der Browser dies ab.
Der Service Worker empfängt das „Push“-Ereignis, entschlüsselt es (verarbeitet vom Browser-Betriebssystem) und zeigt die Benachrichtigung an.
self.registration.showNotification(data.title, { body: data.body, icon: '/icon.png' }).
Warten Sie, bis das Versprechen aufgelöst wird („event.waitUntil“), um sicherzustellen, dass die Benachrichtigung auch dann angezeigt wird, wenn die SW sofort beendet wird.
14. Workbox-Module: Nutzen Sie die Plattform
Erfinden Sie das Rad nicht neu.
„workbox-precaching“, „workbox-routing“, „workbox-strategies“, „workbox-expiration“.
Wir verwenden auch „workbox-window“ im Hauptthread, um mit der SW zu kommunizieren.
const wb = new Workbox('/sw.js'); wb.addEventListener('installed', ...).
Dadurch wird die komplexe „navigator.serviceWorker“-API abstrahiert und Browser-Macken (Safari) behandelt.
15. Die Geschichte des Offline-Webs (AppCache)
Vor Service Workers hatten wir AppCache. Es wurde in drei Worten definiert: „AppCache ist ein Douchebag“. Es war deklarativ, streng und machte alles kaputt. Wenn Sie 1 Byte im Manifest geändert haben, hat der Browser ALLES erneut heruntergeladen. Service Workers ersetzten es durch eine Imperative API. Sie schreiben Code. Sie entscheiden, was zu tun ist. Diese Verlagerung von der Konfiguration zum Code ist der Grund, warum Service Worker dort erfolgreich waren, wo AppCache scheiterte.
16. Die Safari-Hürden (iOS)
Apple hat eine Hassliebe zu PWAs. Sie unterstützen Servicemitarbeiter, aber:
- Speicherung: Sie löschen Daten, wenn sie 7 Tage lang nicht verwendet werden (ITP).
- Push: Wird nur in iOS 16.4+ unterstützt (und der Benutzer MUSS zum Startbildschirm hinzufügen).
- Synchronisierung: Die Hintergrundsynchronisierung ist äußerst eingeschränkt. Wir erstellen „progressive“ Apps. Bedeutung: Sie funktionieren perfekt auf Chrome. In Safari werden sie ordnungsgemäß abgebaut (wenn SW ausfällt, wird auf „Nur Netzwerk“ zurückgegriffen).
17. Fazit
Ein Servicemitarbeiter ist nicht nur für „Offline“ da. Es ist ein Performance-Tool. Es entkoppelt die Startzeit der Anwendung von der Netzwerkqualität. Bei einer fehlerhaften 4G-Verbindung macht ein Servicemitarbeiter den Unterschied zwischen einem Bounce und einem Verkauf.
Bei Maison Code behandeln wir das Netzwerk als „unzuverlässige Infrastruktur“ und integrieren Resilienz in den Kunden.
**[Beauftragen Sie unsere Architekten](/contact)**.