fix(pwa): Endlos-Loop "Neue Version verfügbar" beseitigt
All checks were successful
Build & Publish Docker Image / build-and-push (push) Successful in 1m21s
All checks were successful
Build & Publish Docker Image / build-and-push (push) Successful in 1m21s
Der SW rief bisher im Install-Handler self.skipWaiting() auf — der neue SW übersprang damit die "waiting"-Phase und aktivierte sofort. pwaStore.onUpdateFound feuerte trotzdem auf statechange= "installed" + vorhandenem controller und setzte updateAvailable= true. Ergebnis: Toast erschien, obwohl der SW bereits übernommen hatte, und der Klick auf "Neu laden" löste durch das Timing einen neuen Update-Zyklus aus → Endlosschleife, v.a. im Incognito-Mode wo jede Session neu installiert. Jetzt klassisches Pattern: SW wartet in "installed"-Zustand bis der User den Toast bestätigt; pwaStore.reload() postet SKIP_WAITING an den wartenden SW, lauscht auf controllerchange und reloadet dann erst. Ohne diese Trennung ist der Toast semantisch kaputt. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -41,7 +41,22 @@ class PwaStore {
|
||||
|
||||
reload(): void {
|
||||
this.updateAvailable = false;
|
||||
location.reload();
|
||||
const waiting = this.registration?.waiting;
|
||||
if (!waiting) {
|
||||
// Kein wartender SW — entweder war es nur eine Toast-Anzeige, oder
|
||||
// der SW ist schon aktiv. In beiden Fällen reicht ein Reload.
|
||||
location.reload();
|
||||
return;
|
||||
}
|
||||
// Klassisches Pattern: User-Klick → SKIP_WAITING an den wartenden
|
||||
// SW → controllerchange feuert, wenn der neue SW übernimmt → dann
|
||||
// reloaden wir die Seite, damit sie unter dem neuen SW läuft.
|
||||
navigator.serviceWorker.addEventListener(
|
||||
'controllerchange',
|
||||
() => location.reload(),
|
||||
{ once: true }
|
||||
);
|
||||
waiting.postMessage({ type: 'SKIP_WAITING' });
|
||||
}
|
||||
|
||||
dismiss(): void {
|
||||
|
||||
@@ -20,7 +20,12 @@ self.addEventListener('install', (event) => {
|
||||
(async () => {
|
||||
const cache = await caches.open(SHELL_CACHE);
|
||||
await cache.addAll(SHELL_ASSETS);
|
||||
await self.skipWaiting();
|
||||
// Kein self.skipWaiting() hier — der Client (pwaStore) fragt den
|
||||
// User via UpdateToast, ob der neue SW sofort übernehmen soll, und
|
||||
// schickt dann eine SKIP_WAITING-Message. Ohne diese Trennung
|
||||
// würde pwaStore beim Install-Event fälschlich "Neue Version"
|
||||
// zeigen (weil statechange='installed' + controller=alter SW), und
|
||||
// der neue SW würde einen Tick später ungefragt übernehmen.
|
||||
})()
|
||||
);
|
||||
});
|
||||
@@ -91,6 +96,9 @@ self.addEventListener('message', (event) => {
|
||||
event.waitUntil(runSync(false));
|
||||
} else if (data.type === 'sync-check') {
|
||||
event.waitUntil(runSync(true));
|
||||
} else if (data.type === 'SKIP_WAITING') {
|
||||
// Wird vom pwaStore nach User-Klick auf "Neu laden" geschickt.
|
||||
void self.skipWaiting();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user