🐛(service-worker) force reload new service worker

When multiple tabs are open, the new service worker
can stay in the "waiting" state and not be activated
until the other tabs with the old service worker
are closed.
We fix this by forcing the other tabs to reload
the page when a new service worker is detected.
All tabs will then be reloaded and the new service
worker will be activated.
This commit is contained in:
Anthony LC
2025-03-28 13:14:51 +01:00
committed by Anthony LC
parent 544dd00c16
commit 4ff90abdee
3 changed files with 37 additions and 0 deletions

View File

@@ -21,9 +21,11 @@ describe('useSWRegister', () => {
reject('error');
}),
);
Object.defineProperty(navigator, 'serviceWorker', {
value: {
register: registerSpy,
addEventListener: jest.fn(),
},
writable: true,
});
@@ -31,6 +33,10 @@ describe('useSWRegister', () => {
render(<TestComponent />);
expect(registerSpy).toHaveBeenCalledWith('/service-worker.js?v=123456');
expect(navigator.serviceWorker.addEventListener).toHaveBeenCalledWith(
'controllerchange',
expect.any(Function),
);
});
it('checks service-worker is not register', () => {

View File

@@ -8,9 +8,33 @@ export const useSWRegister = () => {
) {
navigator.serviceWorker
.register(`/service-worker.js?v=${process.env.NEXT_PUBLIC_BUILD_ID}`)
.then((registration) => {
registration.onupdatefound = () => {
const newWorker = registration.installing;
if (!newWorker) {
return;
}
newWorker.onstatechange = () => {
if (
newWorker.state === 'installed' &&
navigator.serviceWorker.controller
) {
newWorker.postMessage({ type: 'SKIP_WAITING' });
}
};
};
})
.catch((err) => {
console.error('Service worker registration failed:', err);
});
const currentController = navigator.serviceWorker.controller;
navigator.serviceWorker.addEventListener('controllerchange', () => {
if (currentController) {
window.location.reload();
}
});
}
}, []);
};

View File

@@ -65,6 +65,13 @@ self.addEventListener('install', function (event) {
event.waitUntil(self.skipWaiting());
});
self.addEventListener('message', (event) => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
if (event.data?.type === 'SKIP_WAITING') {
void self.skipWaiting();
}
});
self.addEventListener('activate', function (event) {
const cacheAllow = SW_VERSION;