Deployment live, PWA noch alt? Service-Worker-Updates ohne Versionschaos prüfen
Service Worker können Nutzer zwischen alten und neuen Release-Generationen festhalten. Prüfen Sie Waiting/Activation, skipWaiting, Cache-Versionen, Update-UX und Rollback.
Deployment live, PWA noch alt? Service-Worker-Updates ohne Versionschaos prüfen
Das Deployment ist erfolgreich. Monitoring zeigt die neue Version. Ein Teammitglied öffnet die Website frisch und sieht den Fix. Eine Kundin meldet eine Stunde später trotzdem genau den Fehler, den Sie gerade behoben haben – und ihr Browser liefert weiterhin alte Oberfläche, altes JavaScript oder einen alten Offline-Fallback.
Bei einer Website mit Service Worker gibt es nach einem Release nicht nur „Server alt“ und „Server neu“. Es kann zusätzlich einen aktiven alten Service Worker, einen bereits installierten wartenden neuen Worker, mehrere offene Tabs und verschiedene Cache-Generationen geben.
Das ist kein Browserfehler. Der aktuelle W3C-Entwurf vom 17. September 2026 beschreibt weiterhin die getrennten Phasen Installation, Warten und Aktivierung. Die Betriebsfrage lautet deshalb: Wie bleiben HTML, JavaScript, Service Worker und API kompatibel, während Nutzer zwischen Release-Generationen wechseln?
Der Service Worker ist Teil des Release-Prozesses
Ein Service Worker kann Requests abfangen und Antworten aus Cache Storage oder aus dem Netzwerk liefern. Damit sitzt er zwischen einer bereits geladenen Anwendung und Ihrem neuen Deployment.
Wird eine neue Worker-Version gefunden, wird sie zunächst installiert. Wenn noch Seiten vom bisherigen Worker kontrolliert werden, wartet die neue Version normalerweise. MDN beschreibt genau diesen Lebenszyklus: Erst wenn die bisherigen Clients nicht mehr im Weg sind, kann der neue Worker regulär aktiv werden.
Das schützt laufende Sitzungen. Der Preis dafür ist wichtig: „Deployment fertig“ bedeutet nicht automatisch „alle Clients laufen auf der neuen Version“.
Vier Zustände, die Support und Entwicklung unterscheiden müssen
- Welche App-Version läuft im Dokument? HTML und JavaScript können in einem lange offenen Tab alt sein.
- Welcher Service Worker kontrolliert das Dokument?
navigator.serviceWorker.controllerzeigt den aktuellen Controller. - Gibt es einen neuen Worker in
waiting? Dann ist ein Update vorhanden, aber noch nicht übernommen. - Welche Cache-Generation beantwortet Requests? Alte Cache-Einträge verschwinden nicht automatisch, nur weil ein neuer Worker installiert wurde.
Wenn diese Zustände nicht sichtbar sind, endet ein Release-Problem schnell mit „Bitte Cache leeren“. Das ist keine Update-Strategie.
skipWaiting() ist kein kostenloser Sofort-Update-Schalter
skipWaiting() kann einen wartenden Worker zur schnellen Aktivierung bringen. Zusammen mit clients.claim() kann der neue Worker anschließend sogar bereits offene Seiten kontrollieren.
Das klingt attraktiv, erzeugt aber potenziell eine gemischte Generation. web.dev warnt ausdrücklich: Ein sofort aktivierter Worker kann eine Seite übernehmen, die noch mit der alten Anwendungsversion geladen wurde. Frühere Requests liefen über Worker A, spätere über Worker B.
Beispiel:
- Version A lädt
app-A.jsund erwartet API-Format A. - Version B installiert einen neuen Worker mit anderer Cache-Logik.
skipWaiting()aktiviert B sofort.- Der offene Tab führt weiterhin JavaScript A aus, seine nächsten Fetches laufen aber durch Worker B.
Wenn beide Generationen kompatibel sind, ist das okay. Wenn nicht, entsteht ein Fehler, der fast nur in lang geöffneten Tabs auftritt.
Die richtige Frage ist daher nicht „Können wir sofort aktivieren?“, sondern: Ist ein alter Client nach dem Worker-Wechsel garantiert noch kompatibel?
Drei saubere Update-Modelle
1. Natürlich warten
Der neue Worker bleibt in waiting, bis alte kontrollierte Clients verschwunden sind. Das ist robust, wenn lange Sitzungen akzeptabel sind und ältere Server-/Asset-Versionen ausreichend lange unterstützt werden.
2. Update anbieten und kontrolliert neu laden
Die Seite erkennt über updatefound oder einen wartenden Worker, dass eine neue Version bereitsteht. Die UI zeigt etwa „Neue Version verfügbar“. Erst nach Nutzeraktion wird skipWaiting() ausgelöst. Beim folgenden controllerchange wird die Anwendung einmal kontrolliert neu geladen.
Damit wechseln Dokument, JavaScript und Worker gemeinsam. Das eignet sich besonders für Dashboards, Editoren und SaaS-Produkte, bei denen ein spontaner Reload Eingaben zerstören könnte.
3. Sofort übernehmen – mit Kompatibilitätsvertrag
Ein Produkt kann skipWaiting() und clients.claim() bewusst automatisch einsetzen. Dann muss die Architektur dafür ausgelegt sein, dass alte und neue Clients zeitweise dieselbe API und dieselbe Cache-Schicht nutzen.
Das ist ein Release-Vertrag, kein Einzeiler im Worker.
Cache-Versionierung muss zur Aktivierung passen
web.dev weist darauf hin, dass die Installation eines neuen Workers alte Cache-Inhalte nicht automatisch entfernt. Cache-Namen, Precache-Manifest und Cleanup brauchen deshalb eine nachvollziehbare Versionierung.
Ein typisches Muster schreibt neue Assets in einen neuen Cache und entfernt alte Caches beim activate-Schritt. Aber auch hier kann Cleanup zu früh kommen. Wenn ein alter Tab später noch einen Lazy Chunk aus Generation A benötigt und der neue Worker sämtliche A-Caches sofort gelöscht hat, kann der Tab plötzlich brechen.
Hash-basierte Asset-Dateinamen helfen, mehrere Generationen parallel bereitzuhalten. Der Deployment-Prozess sollte vorige Assets nicht in derselben Sekunde löschen, in der neues HTML live geht.
Update gefunden ist nicht Update aktiv
ServiceWorkerRegistration.update() stößt eine Prüfung des Worker-Skripts an. Ist die neue Version byteweise unterschiedlich, beginnt der Update-Lebenszyklus. updatefound signalisiert, dass eine neue Installation gestartet ist.
Für Monitoring und UI sollten Sie unterscheiden:
- Update-Prüfung gestartet ≠ installiert.
- Installiert ≠ aktiv.
- Waiting ≠ vom aktuellen Tab verwendet.
- Aktiviert ≠ Dokument bereits neu geladen.
Eine Statusanzeige „App aktuell“, die diese Stufen zusammenwirft, kann falsche Sicherheit geben.
Lange offene Tabs sind der echte Härtetest
Der wichtigste Test ist nicht der frische Inkognito-Tab. Der schwierige Fall ist ein Client, der vor dem Deployment geöffnet wurde.
Testen Sie mindestens:
- Version A öffnen und angemeldet lassen.
- Einen zweiten Tab oder ein installiertes PWA-Fenster öffnen.
- Version B deployen.
- Prüfen, wann
updatefounderscheint und ob B inwaitinglandet. - Im alten Tab weiterarbeiten: Navigation, API-Calls, Lazy Imports, Uploads und Formulare.
- Den vorgesehenen Update-Flow auslösen.
- Prüfen, dass genau ein sauberer Reload entsteht und keine Reload-Schleife.
- Offline-Zustand während des Updates simulieren.
- Prüfen, ob alte und neue Clients anschließend auf dieselbe Version konvergieren.
- Einen Rollback oder ein fehlerhaftes B-Deployment simulieren.
Wenn ein Release nur im frischen Browserprofil funktioniert, ist der Test zu freundlich.
API-Kompatibilität gehört dazu
Ein alter Tab kann weiterhin JavaScript A ausführen, während der Server bereits API B liefert. PWA-Releases haben deshalb dieselbe Realität wie andere verteilte Systeme: Mehrere Client-Versionen können gleichzeitig existieren.
Brechende API-Änderungen sollten nicht voraussetzen, dass jeder Browser innerhalb von Sekunden aktualisiert. Versionierte Endpunkte, Kompatibilitätsfenster, Feature Flags oder eine klar erkannte Mindestversion mit verständlichem Reload-Pfad sind deutlich belastbarer.
Ein Service Worker kann Updates beschleunigen. Er kann inkompatible Client-/Server-Verträge nicht wegzaubern.
Ein Server-Rollback ist noch kein Client-Rollback
Wenn Version B Probleme macht und Sie den Server auf A zurücksetzen, bleiben Service-Worker-Registrierungen und Cache Storage auf Geräten bestehen. Deshalb sollte ein Rollback-Plan beantworten:
- Welche Worker-Version kontrolliert bestehende Clients?
- Welche Cache-Generationen existieren noch?
- Sind alte Assets am Origin oder CDN noch verfügbar?
- Kann der zurückgerollte Server mit Clients aus B sprechen?
- Brauchen Sie einen Korrektur-Worker statt nur ein Git-Revert?
- Wie erfahren Nutzer, dass ein Reload nötig ist?
Rollback ist ein Release-Pfad in beide Richtungen, nicht nur eine Server-Aktion.
Was Website-Pflichtencheck prüfen würde
Ein Service-Worker-/PWA-Release-Audit kann unter anderem prüfen:
- Registrierung, Scope und tatsächlich ausgelieferte Worker-Datei,
install,waiting,activateundcontrollerchange,- Einsatz von
skipWaiting()undclients.claim(), - Update-Erkennung über
updatefoundund expliziteupdate()-Checks, - Cache-Namen, Versionierung und Cleanup,
- Verhalten alter Tabs während eines Deployments,
- Hash-Assets und Aufbewahrung vorheriger Generationen,
- Update-UI und kontrollierte Reloads,
- Offline-Verhalten während eines Versionswechsels,
- API-Kompatibilität zwischen alten und neuen Clients,
- Rollback- und Recovery-Pfade.
Das Ziel ist nicht, jeden Nutzer in derselben Millisekunde auf die neue Version zu zwingen. Das Ziel ist ein Release-Modell, das erklären kann, welcher Client gerade welche Generation ausführt, wie er sicher zur nächsten wechselt und was passiert, wenn ein Deployment zurückgenommen werden muss.
Wenn „Cache leeren und neu laden“ der wichtigste Support-Schritt Ihrer PWA ist, fehlt sehr wahrscheinlich ein sichtbarer, getesteter Update-Vertrag zwischen Browser und Deployment.