From 4ff90abdee8633202bf81383562153050129ea58 Mon Sep 17 00:00:00 2001 From: Anthony LC Date: Fri, 28 Mar 2025 13:14:51 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B(service-worker)=20force=20reload?= =?UTF-8?q?=20new=20service=20worker?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- .../__tests__/useSWRegister.test.tsx | 6 +++++ .../service-worker/hooks/useSWRegister.tsx | 24 +++++++++++++++++++ .../features/service-worker/service-worker.ts | 7 ++++++ 3 files changed, 37 insertions(+) diff --git a/src/frontend/apps/impress/src/features/service-worker/__tests__/useSWRegister.test.tsx b/src/frontend/apps/impress/src/features/service-worker/__tests__/useSWRegister.test.tsx index 36f4ad4fd..1698907cd 100644 --- a/src/frontend/apps/impress/src/features/service-worker/__tests__/useSWRegister.test.tsx +++ b/src/frontend/apps/impress/src/features/service-worker/__tests__/useSWRegister.test.tsx @@ -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(); expect(registerSpy).toHaveBeenCalledWith('/service-worker.js?v=123456'); + expect(navigator.serviceWorker.addEventListener).toHaveBeenCalledWith( + 'controllerchange', + expect.any(Function), + ); }); it('checks service-worker is not register', () => { diff --git a/src/frontend/apps/impress/src/features/service-worker/hooks/useSWRegister.tsx b/src/frontend/apps/impress/src/features/service-worker/hooks/useSWRegister.tsx index eadeecc72..da897cff5 100644 --- a/src/frontend/apps/impress/src/features/service-worker/hooks/useSWRegister.tsx +++ b/src/frontend/apps/impress/src/features/service-worker/hooks/useSWRegister.tsx @@ -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(); + } + }); } }, []); }; diff --git a/src/frontend/apps/impress/src/features/service-worker/service-worker.ts b/src/frontend/apps/impress/src/features/service-worker/service-worker.ts index 77a4f257e..b8950beb2 100644 --- a/src/frontend/apps/impress/src/features/service-worker/service-worker.ts +++ b/src/frontend/apps/impress/src/features/service-worker/service-worker.ts @@ -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;