mit Workbox und next-pwa
Eine React-App, die beim ersten Netzwerkausfall weißen Screen zeigt, ist keine Progressive Web App – sie ist eine Website mit Icon. Echter Offline-First-Betrieb erfordert durchdachte Caching-Strategien, Background Sync und einen Service Worker, der weiß, was er cachen darf und was nicht.
Inhaltsverzeichnis
- 1. Was eine echte PWA von einer normalen Web-App unterscheidet
- 2. Service Worker: Lebenszyklus und Registrierung
- 3. Workbox: Caching-Strategien im Detail
- 4. next-pwa: Integration in Next.js-Projekte
- 5. Precaching: App-Shell und kritische Assets sichern
- 6. Background Sync: Offline-Aktionen nachholen
- 7. Push-Notifications mit Web Push API
- 8. Service-Worker-Updates und Versionierung
- 9. Caching-Strategien im Vergleich
- 10. Zusammenfassung
- 11. FAQ
1. Was eine echte PWA von einer normalen Web-App unterscheidet
Der Begriff Progressive Web App wird oft mit „installierbar" gleichgesetzt. Das ist zu kurz gedacht. Eine installierbare App, die ohne Netzwerk nichts anzeigt, erfüllt keine der Versprechen, die PWA eigentlich geben soll: zuverlässiges Laden, unabhängig von der Netzwerksituation des Nutzers. Die technische Grundlage dafür ist kein Web-App-Manifest, sondern ein Service Worker mit einer durchdachten Caching-Strategie.
Offline-First bedeutet nicht „zeig eine Offline-Seite, wenn kein Netz da ist". Es bedeutet, dass die App standardmäßig aus dem Cache bedient wird und das Netzwerk nur für Updates verwendet. Dieser Ansatz verbessert nicht nur die Robustheit bei Netzwerkausfällen, sondern auch die wahrgenommene Ladegeschwindigkeit erheblich – Assets kommen aus dem lokalen Cache statt aus dem Netz. Für React-Apps lässt sich dieses Muster mit Workbox und bei Next.js-Projekten mit next-pwa systematisch umsetzen.
2. Service Worker: Lebenszyklus und Registrierung
Ein Service Worker ist ein JavaScript-Skript, das der Browser im Hintergrund ausführt – getrennt vom Haupt-Thread, ohne Zugriff auf das DOM. Er fungiert als Netzwerk-Proxy zwischen der App und dem Server und kann Requests abfangen, aus dem Cache beantworten oder modifizieren. Sein Lebenszyklus besteht aus den Phasen Install, Activate und Fetch. Beim Install werden Assets precached; beim Activate werden alte Caches gelöscht; im Fetch-Event wird jeder ausgehende Request behandelt.
Die Registrierung des Service Workers erfolgt beim App-Start. Wichtig: Der Service Worker darf erst registriert werden, nachdem die Seite geladen ist – sonst konkurriert er mit dem initialen Ladevorgang um Bandbreite. Das Standard-Muster ist daher eine Registrierung im load-Event. Für React-Apps mit Create React App existiert das serviceWorkerRegistration.ts-Paket; Next.js-Projekte delegieren die Registrierung an next-pwa, das sie automatisch ins Build integriert. Der Service Worker muss aus dem Root-Scope der Domain ausgeliefert werden, da sein Scope durch seinen Pfad definiert wird.
// service-worker-registration.ts — Register SW only after page load
// to avoid competing with initial page resources
export function register(): void {
if (
typeof window !== 'undefined' &&
'serviceWorker' in navigator &&
process.env.NODE_ENV === 'production'
) {
window.addEventListener('load', () => {
navigator.serviceWorker
.register('/sw.js')
.then((registration) => {
console.log('[SW] Registered, scope:', registration.scope);
// Detect available update
registration.addEventListener('updatefound', () => {
const worker = registration.installing;
if (!worker) return;
worker.addEventListener('statechange', () => {
if (
worker.state === 'installed' &&
navigator.serviceWorker.controller
) {
// New version available — notify user
dispatchEvent(new CustomEvent('sw-update-available'));
}
});
});
})
.catch((err) => console.error('[SW] Registration failed:', err));
});
}
}
3. Workbox: Caching-Strategien im Detail
Workbox ist Googles Bibliothek für Service-Worker-Logik und abstrahiert die rohe Cache-API in wiederverwendbare Strategien. Die wichtigste Entscheidung beim PWA-Aufbau ist, welche Strategie für welchen Asset-Typ passt. Es gibt fünf Grundstrategien: Cache First, Network First, Stale While Revalidate, Network Only und Cache Only. Jede hat ihre Berechtigung, und der Fehler liegt meist im falschen Einsatz – etwa wenn API-Aufrufe mit Cache First behandelt werden und veraltete Daten liefern.
Cache First passt für Fonts, Icons und statische Bilder, die sich nie ändern. Stale While Revalidate ist ideal für JavaScript- und CSS-Bundles – der Nutzer bekommt sofort das gecachte Asset, während im Hintergrund eine neue Version geladen wird. Network First eignet sich für API-Responses, die aktuell sein müssen, aber bei Offline-Betrieb aus dem Cache als Fallback dienen sollen. Die Konfiguration mit Workbox erfolgt direkt in der Service-Worker-Datei und wird über workbox-webpack-plugin oder den Workbox CLI in den Build-Prozess integriert.
4. next-pwa: Integration in Next.js-Projekte
next-pwa ist ein Next.js-Plugin, das Workbox automatisch in den Build-Prozess integriert. Es generiert beim Build einen optimierten Service Worker aus dem Workbox-Build und fügt ihn in den public-Ordner ein. Die Konfiguration erfolgt in next.config.js über wenige Parameter. Entscheidend ist, PWA im Development-Modus zu deaktivieren, da Service Worker mit Hot-Module-Replacement interferieren und das Debugging erheblich erschweren.
next-pwa übernimmt das Precaching aller Next.js-Chunks automatisch. Für benutzerdefinierte Routen und API-Endpoints müssen Runtime-Caching-Regeln explizit definiert werden. Die Bibliothek unterstützt auch Workbox-InjectManifest-Modus, bei dem man die Service-Worker-Datei selbst schreibt und nur die Precaching-Manifest-Injection übernommen wird. Das gibt vollständige Kontrolle über alle Strategien bei gleichzeitiger Build-Integration.
// next.config.js — next-pwa configuration with Workbox runtime caching
const withPWA = require('next-pwa')({
dest: 'public',
disable: process.env.NODE_ENV === 'development', // Disable in dev
register: true,
skipWaiting: true,
// Custom runtime caching rules
runtimeCaching: [
{
// Cache API responses with Network First (fallback to cache)
urlPattern: /^https:\/\/api\.mironsoft\.de\/.*/i,
handler: 'NetworkFirst',
options: {
cacheName: 'api-cache',
expiration: { maxEntries: 50, maxAgeSeconds: 300 }, // 5 min TTL
networkTimeoutSeconds: 10,
cacheableResponse: { statuses: [0, 200] },
},
},
{
// Stale While Revalidate for JS/CSS bundles
urlPattern: /\/_next\/static\/.*/i,
handler: 'StaleWhileRevalidate',
options: { cacheName: 'static-resources' },
},
{
// Cache First for images (long TTL)
urlPattern: /\.(?:png|jpg|jpeg|webp|avif|svg|ico)$/i,
handler: 'CacheFirst',
options: {
cacheName: 'image-cache',
expiration: { maxEntries: 200, maxAgeSeconds: 2592000 }, // 30 days
},
},
],
});
module.exports = withPWA({ reactStrictMode: true });
5. Precaching: App-Shell und kritische Assets sichern
Precaching ist das Herzstück des Offline-First-Ansatzes. Beim Service-Worker-Install werden alle kritischen Assets in den Cache geladen – bevor der Nutzer sie überhaupt braucht. Das Ergebnis: Beim nächsten Aufruf, egal ob online oder offline, sind alle App-Shell-Assets sofort verfügbar. Workbox verwaltet das Precaching-Manifest automatisch und invalidiert Einträge, wenn sich der Content-Hash einer Datei ändert. Das verhindert sowohl veraltete Caches als auch unnötige Re-Downloads unveränderter Dateien.
Für Next.js-Apps enthält das Precaching-Manifest alle generierten Chunks, CSS-Dateien und statischen Assets. Dynamische Routen erfordern besondere Überlegung: Soll die Shell einer Route precached werden, muss die Route zum Zeitpunkt des Builds bekannt sein. Unbekannte Routen können über Runtime-Caching mit Network First behandelt werden, sodass sie beim ersten Besuch gecacht und danach offline verfügbar sind. Die Kombination aus App-Shell-Precaching und Route-Runtime-Caching deckt die meisten Szenarien ab.
6. Background Sync: Offline-Aktionen nachholen
Background Sync löst das Problem, dass Nutzer beim Offline-Betrieb keine Daten senden können – Formularabsendungen, Like-Aktionen oder Bestellungen schlagen fehl. Mit der Background Sync API registriert der Service Worker einen Sync-Tag, wenn eine Netzwerkanfrage offline schlägt. Sobald die Verbindung wiederhergestellt ist, löst der Browser das sync-Event aus und der Service Worker holt die Aktion nach. Der Nutzer bemerkt nichts davon – seine Aktion wurde nur verzögert, nicht verworfen.
Die Implementierung besteht aus zwei Teilen: Im App-Code wird der fehlgeschlagene Request in IndexedDB gespeichert und ein Sync-Tag registriert. Im Service Worker wird beim sync-Event die IndexedDB ausgelesen und alle ausstehenden Requests werden wiederholt. Workbox stellt mit workbox-background-sync eine fertige Queue-Implementierung bereit, die das manuelle Verwalten von IndexedDB erspart. Für kritische Daten wie Bestellungen empfiehlt sich zusätzlich eine serverseitige Idempotenz, da das Sync-Event mehrfach feuern kann.
// custom-sw.ts — Background Sync with Workbox Queue
import { BackgroundSyncPlugin } from 'workbox-background-sync';
import { registerRoute } from 'workbox-routing';
import { NetworkOnly } from 'workbox-strategies';
import { precacheAndRoute } from 'workbox-precaching';
// Precache all assets injected by Workbox build
declare const self: ServiceWorkerGlobalScope & { __WB_MANIFEST: any[] };
precacheAndRoute(self.__WB_MANIFEST);
// Background Sync Queue for POST requests to API
const bgSyncPlugin = new BackgroundSyncPlugin('api-queue', {
maxRetentionTime: 24 * 60, // Retain for 24 hours (in minutes)
onSync: async ({ queue }) => {
let entry;
while ((entry = await queue.shiftRequest())) {
try {
await fetch(entry.request.clone());
console.log('[SW] Replayed queued request:', entry.request.url);
} catch (err) {
// Put it back if it still fails
await queue.unshiftRequest(entry);
throw err;
}
}
},
});
// Use NetworkOnly + BackgroundSync for mutation endpoints
registerRoute(
({ url }) => url.pathname.startsWith('/api/') && url.method === 'POST',
new NetworkOnly({ plugins: [bgSyncPlugin] }),
'POST'
);
7. Push-Notifications mit Web Push API
Push-Notifications sind der dritte Pfeiler einer vollständigen PWA neben Offline-First und Installierbarkeit. Sie erlauben es, Nutzer auch dann zu erreichen, wenn die App nicht geöffnet ist. Technisch basieren sie auf dem Web Push Protocol: Der Browser erstellt ein Push-Subscription-Objekt, das an den Server gesendet wird. Der Server schickt verschlüsselte Nachrichten über den Push-Dienst des Browser-Anbieters, der sie an den Service Worker zustellt.
Die Implementierung erfordert VAPID-Schlüssel (Voluntary Application Server Identification), die serverseitig generiert werden. Im Frontend wird die Subscription mit registration.pushManager.subscribe() angefordert, was eine Benutzererlaubnis voraussetzt. Im Service Worker wird das push-Event behandelt und die Notification über self.registration.showNotification() angezeigt. Für React-Apps empfiehlt sich ein Custom Hook, der den Subscription-Status verwaltet und als Context bereitstellt, damit Komponenten gezielt auf den Notification-Status reagieren können.
8. Service-Worker-Updates und Versionierung
Der schwierigste Teil einer PWA ist die Update-Verwaltung. Wenn ein neuer Service Worker verfügbar ist, wartet er zunächst im Zustand waiting, bis alle Tabs der App geschlossen werden. Das bedeutet, Nutzer können stundenlang eine veraltete Version laufen haben, ohne es zu merken. Die Lösung ist eine sichtbare Update-Benachrichtigung im UI: Wenn ein neuer Service Worker erkannt wird, zeigt die App einen Toast oder Banner, der den Nutzer auffordert, die Seite neu zu laden.
Das skipWaiting()-Muster aktiviert den neuen Service Worker sofort, ohne auf geschlossene Tabs zu warten. Das birgt jedoch Risiken: Wenn mehrere Tabs offen sind und unterschiedliche Service-Worker-Versionen kontrollieren, können Inkonsistenzen auftreten. Die sicherere Variante ist, skipWaiting() nur auf explizite Nutzeraktion hin aufzurufen – über eine postMessage an den wartenden Worker. Das gibt die Kontrolle dem Nutzer und verhindert überraschende Reloads während einer Bestellung oder eines Formulars.
9. Caching-Strategien im Vergleich
Die Wahl der richtigen Caching-Strategie hängt von zwei Dimensionen ab: Wie wichtig ist Aktualität, und wie wichtig ist Verfügbarkeit bei Offline-Betrieb? Die folgende Tabelle ordnet die fünf Workbox-Strategien diesen Dimensionen zu.
| Strategie | Offline-Verfügbarkeit | Aktualität | Einsatzgebiet |
|---|---|---|---|
| Cache First | Hoch | Niedrig | Fonts, Icons, unveränderliche Bilder |
| Network First | Mittel (Fallback) | Hoch | API-Responses, HTML-Seiten |
| Stale While Revalidate | Hoch | Mittel (verzögert) | JS/CSS-Bundles, Avatare |
| Network Only | Keine | Hoch | Zahlungen, Auth-Token-Refresh |
| Cache Only | Hoch | Keine | App-Shell nach Precaching |
In der Praxis kombiniert eine vollständige PWA immer mehrere Strategien. Der häufigste Fehler ist, eine einzige Strategie für alle Requests zu verwenden – meist Cache First für alles, was zu veralteten API-Daten führt, oder Network First für alles, was den Offline-Vorteil zunichtemacht. Workbox ermöglicht granulare Regeln per URL-Pattern, sodass jeder Asset-Typ optimal behandelt werden kann.
Mironsoft
React PWA · Workbox · Offline-First-Architektur
React-App zur vollständigen PWA ausbauen?
Wir analysieren eure bestehende React-App und implementieren eine Offline-First-Architektur mit Workbox – inklusive Caching-Strategie, Background Sync und Update-Management.
PWA-Audit
Lighthouse-Analyse und Identifikation von Offline-Schwachstellen in eurer App
Workbox-Setup
Passende Caching-Strategien, Precaching und Background Sync implementieren
Update-Handling
Sicheres Service-Worker-Update-Management und Nutzerbenachrichtigung
10. Zusammenfassung
Eine echte React PWA mit Workbox besteht aus mehreren ineinandergreifenden Teilen: einem korrekt registrierten Service Worker, einer asset-typgerechten Caching-Strategie, Precaching der App-Shell und optionalem Background Sync für Offline-Aktionen. Workbox abstrahiert die Cache-API und macht Strategien konfigurierbar, ohne jedes Detail manuell implementieren zu müssen. next-pwa integriert Workbox nahtlos in den Next.js-Build und übernimmt das Precaching aller Chunks automatisch.
Der entscheidende Schritt ist die bewusste Entscheidung pro Asset-Typ: Was muss immer aktuell sein, was darf gecacht werden, was muss auch offline funktionieren? Diese Differenzierung – und nicht die bloße Installation eines Service Workers – macht den Unterschied zwischen einer echten Offline-First-App und einer normalen Web-App mit Manifest-Datei. Update-Management und Background Sync runden das Bild ab und sorgen dafür, dass Nutzer stets eine konsistente Erfahrung haben.
React PWA mit Workbox — Das Wichtigste auf einen Blick
Caching-Strategie
Cache First für statische Assets, Network First für APIs, Stale While Revalidate für Bundles – nie eine Einheitsstrategie für alles.
Precaching
App-Shell und kritische Assets beim SW-Install precachen. Workbox verwaltet Content-Hashes und invalidiert nur geänderte Dateien.
Background Sync
Offline-Aktionen in IndexedDB zwischenspeichern, bei Reconnect nachholen. workbox-background-sync liefert die Queue-Implementierung.
Update-Management
skipWaiting nur auf Nutzeraktion. Neue SW-Versionen per CustomEvent signalisieren und im UI als Update-Banner anzeigen.