fix: send SKIP_WAITING to waiting SW, not active controller, to break reload loop
This commit is contained in:
@@ -2796,7 +2796,12 @@ function pollBuildTag() {
|
|||||||
// PWA — service worker registration and update banner (WEB mode only)
|
// PWA — service worker registration and update banner (WEB mode only)
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
function showUpdateBanner() {
|
let _updateBannerShown = false;
|
||||||
|
function showUpdateBanner(waitingSW) {
|
||||||
|
// Only show the banner once per page load
|
||||||
|
if (_updateBannerShown) return;
|
||||||
|
_updateBannerShown = true;
|
||||||
|
|
||||||
// Use a persistent, click-to-reload toast instead of the standard 2.2s one
|
// Use a persistent, click-to-reload toast instead of the standard 2.2s one
|
||||||
const t = document.createElement('div');
|
const t = document.createElement('div');
|
||||||
t.className = 'toast toast-update';
|
t.className = 'toast toast-update';
|
||||||
@@ -2804,13 +2809,15 @@ function showUpdateBanner() {
|
|||||||
const container = $('toastContainer');
|
const container = $('toastContainer');
|
||||||
container.appendChild(t);
|
container.appendChild(t);
|
||||||
t.querySelector('.toast-reload-btn').addEventListener('click', () => {
|
t.querySelector('.toast-reload-btn').addEventListener('click', () => {
|
||||||
// Tell the waiting SW to skip waiting, then reload once it takes control.
|
if (waitingSW) {
|
||||||
if (navigator.serviceWorker.controller) {
|
// Signal the *waiting* SW (not the active controller) to take over.
|
||||||
navigator.serviceWorker.controller.postMessage({ type: 'SKIP_WAITING' });
|
// Once it does, controllerchange fires and we reload.
|
||||||
|
waitingSW.postMessage({ type: 'SKIP_WAITING' });
|
||||||
|
navigator.serviceWorker.addEventListener('controllerchange', () => window.location.reload(), { once: true });
|
||||||
|
} else {
|
||||||
|
// No waiting SW (e.g. build-tag or SW_UPDATE_AVAILABLE path) — just reload.
|
||||||
|
window.location.reload();
|
||||||
}
|
}
|
||||||
navigator.serviceWorker.addEventListener('controllerchange', () => window.location.reload(), { once: true });
|
|
||||||
// Fallback: reload after a short delay in case controllerchange already fired
|
|
||||||
setTimeout(() => window.location.reload(), 500);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2821,20 +2828,21 @@ async function registerServiceWorker() {
|
|||||||
|
|
||||||
// If a new SW is already waiting (e.g. user refreshed after an update),
|
// If a new SW is already waiting (e.g. user refreshed after an update),
|
||||||
// show the banner right away.
|
// show the banner right away.
|
||||||
if (reg.waiting) { showUpdateBanner(); return; }
|
if (reg.waiting) { showUpdateBanner(reg.waiting); return; }
|
||||||
|
|
||||||
// Listen for a new SW installing after the page is open.
|
// Listen for a new SW installing after the page is open.
|
||||||
reg.addEventListener('updatefound', () => {
|
reg.addEventListener('updatefound', () => {
|
||||||
const sw = reg.installing;
|
const sw = reg.installing;
|
||||||
if (!sw) return;
|
if (!sw) return;
|
||||||
sw.addEventListener('statechange', () => {
|
sw.addEventListener('statechange', () => {
|
||||||
if (sw.state === 'installed' && reg.waiting) showUpdateBanner();
|
if (sw.state === 'installed' && reg.waiting) showUpdateBanner(reg.waiting);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// The SW can also broadcast SW_UPDATE_AVAILABLE on its own activate
|
// The SW can also broadcast SW_UPDATE_AVAILABLE on its own activate.
|
||||||
|
// In this case the new SW is already active, so just reload directly.
|
||||||
navigator.serviceWorker.addEventListener('message', (e) => {
|
navigator.serviceWorker.addEventListener('message', (e) => {
|
||||||
if (e.data && e.data.type === 'SW_UPDATE_AVAILABLE') showUpdateBanner();
|
if (e.data && e.data.type === 'SW_UPDATE_AVAILABLE') showUpdateBanner(null);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Check for updates in the background (useful for long-lived sessions)
|
// Check for updates in the background (useful for long-lived sessions)
|
||||||
|
|||||||
Reference in New Issue
Block a user