diff --git a/client.d.ts b/client.d.ts index b01f4954..2d791a33 100644 --- a/client.d.ts +++ b/client.d.ts @@ -20,6 +20,12 @@ declare module 'virtual:pwa-register' { onRegisterError?: (error: any) => void } + /** + * Registers the service worker returning a callback to reload the current page when an update is found. + * + * @param options the options to register the service worker. + * @return (reloadPage?: boolean) => Promise From version 0.13.2+ `reloadPage` param is not used anymore. + */ export function registerSW(options?: RegisterSWOptions): (reloadPage?: boolean) => Promise } @@ -52,6 +58,11 @@ declare module 'virtual:pwa-register/vue' { export function useRegisterSW(options?: RegisterSWOptions): { needRefresh: Ref offlineReady: Ref + /** + * Reloads the current window to allow the service worker take the control. + * + * @param reloadPage From version 0.13.2+ this param is not used anymore. + */ updateServiceWorker: (reloadPage?: boolean) => Promise } } @@ -85,6 +96,11 @@ declare module 'virtual:pwa-register/svelte' { export function useRegisterSW(options?: RegisterSWOptions): { needRefresh: Writable offlineReady: Writable + /** + * Reloads the current window to allow the service worker take the control. + * + * @param reloadPage From version 0.13.2+ this param is not used anymore. + */ updateServiceWorker: (reloadPage?: boolean) => Promise } } @@ -118,6 +134,11 @@ declare module 'virtual:pwa-register/react' { export function useRegisterSW(options?: RegisterSWOptions): { needRefresh: [boolean, Dispatch>] offlineReady: [boolean, Dispatch>] + /** + * Reloads the current window to allow the service worker take the control. + * + * @param reloadPage From version 0.13.2+ this param is not used anymore. + */ updateServiceWorker: (reloadPage?: boolean) => Promise } } @@ -151,6 +172,11 @@ declare module 'virtual:pwa-register/solid' { export function useRegisterSW(options?: RegisterSWOptions): { needRefresh: [Accessor, Setter] offlineReady: [Accessor, Setter] + /** + * Reloads the current window to allow the service worker take the control. + * + * @param reloadPage From version 0.13.2+ this param is not used anymore. + */ updateServiceWorker: (reloadPage?: boolean) => Promise } } @@ -184,6 +210,11 @@ declare module 'virtual:pwa-register/preact' { export function useRegisterSW(options?: RegisterSWOptions): { needRefresh: [boolean, StateUpdater] offlineReady: [boolean, StateUpdater] + /** + * Reloads the current window to allow the service worker take the control. + * + * @param reloadPage From version 0.13.2+ this param is not used anymore. + */ updateServiceWorker: (reloadPage?: boolean) => Promise } } diff --git a/docs/.vitepress/components.d.ts b/docs/.vitepress/components.d.ts index 9b2f4709..9e728017 100644 --- a/docs/.vitepress/components.d.ts +++ b/docs/.vitepress/components.d.ts @@ -13,7 +13,6 @@ declare module '@vue/runtime-core' { ExamplesInjectManifest: typeof import('./theme/components/ExamplesInjectManifest.md')['default'] GenerateSWCleanupOutdatedCaches: typeof import('./theme/components/GenerateSWCleanupOutdatedCaches.md')['default'] GenerateSWSourceMap: typeof import('./theme/components/GenerateSWSourceMap.md')['default'] - HeuristicWorkboxWindow: typeof import('./theme/components/HeuristicWorkboxWindow.md')['default'] HomePage: typeof import('./theme/components/HomePage.vue')['default'] InjectManifestCleanupOutdatedCaches: typeof import('./theme/components/InjectManifestCleanupOutdatedCaches.md')['default'] InjectManifestSourceMap: typeof import('./theme/components/InjectManifestSourceMap.md')['default'] diff --git a/docs/.vitepress/theme/components/HeuristicWorkboxWindow.md b/docs/.vitepress/theme/components/HeuristicWorkboxWindow.md deleted file mode 100644 index 8cc540dc..00000000 --- a/docs/.vitepress/theme/components/HeuristicWorkboxWindow.md +++ /dev/null @@ -1,5 +0,0 @@ -::: warning -**This only applies when importing any of the virtual modules or using `workbox-window` module**. - -Since `workbox-window` uses a time-based `heuristic` algorithm to handle service worker updates, if you build your service worker and register it again, if the time between last registration and the new one is less than 1 minute, then, `workbox-window` will handle the `service worker update found` event as an external event, and so the behavior could be strange (for example, if using `prompt`, instead showing the dialog for new content available, the ready to work offline dialog will be shown; if using `autoUpdate`, the ready to work offline dialog will be shown and shouldn't be shown). -::: diff --git a/docs/examples/preact.md b/docs/examples/preact.md index c023a0cc..93c75a3a 100644 --- a/docs/examples/preact.md +++ b/docs/examples/preact.md @@ -31,9 +31,6 @@ Done. Now run: To test `new content available`, you should rerun the corresponding script, and then refresh the page. -If you are running an example with `Periodic SW updates`, you will need to wait 1 minute: - - ## Executing the examples diff --git a/docs/examples/react.md b/docs/examples/react.md index 739dcca1..4c371191 100644 --- a/docs/examples/react.md +++ b/docs/examples/react.md @@ -31,9 +31,6 @@ Done. Now run: To test `new content available`, you should rerun the corresponding script, and then refresh the page. -If you are running an example with `Periodic SW updates`, you will need to wait 1 minute: - - ## Executing the examples diff --git a/docs/examples/solidjs.md b/docs/examples/solidjs.md index 7c28e605..c4a88f6f 100644 --- a/docs/examples/solidjs.md +++ b/docs/examples/solidjs.md @@ -20,9 +20,6 @@ npx degit solidjs/templates/ts-router solid-router To test `new content available`, you should rerun the corresponding script, and then refresh the page. -If you are running an example with `Periodic SW updates`, you will need to wait 1 minute: - - ## Executing the examples diff --git a/docs/examples/svelte.md b/docs/examples/svelte.md index be0d885c..c64f71c4 100644 --- a/docs/examples/svelte.md +++ b/docs/examples/svelte.md @@ -30,9 +30,6 @@ Done. Now run: To test `new content available`, you should rerun the corresponding script, and then refresh the page. -If you are running an example with `Periodic SW updates`, you will need to wait 1 minute: - - ## Executing the examples diff --git a/docs/examples/sveltekit.md b/docs/examples/sveltekit.md index f6c40c73..8ee8584e 100644 --- a/docs/examples/sveltekit.md +++ b/docs/examples/sveltekit.md @@ -47,10 +47,6 @@ Next steps: To test `new content available`, you should rerun the corresponding script, and then refresh the page. -If you are running an example with `Periodic SW updates`, you will need to wait 1 minute: - - - ## Executing the examples diff --git a/docs/examples/vue.md b/docs/examples/vue.md index a12bf7a4..8833925c 100644 --- a/docs/examples/vue.md +++ b/docs/examples/vue.md @@ -31,9 +31,6 @@ Done. Now run: To test `new content available`, you should rerun the corresponding script, and then refresh the page. -If you are running an example with `Periodic SW updates`, you will need to wait 1 minute: - - ## Executing the examples diff --git a/docs/frameworks/preact.md b/docs/frameworks/preact.md index 1f36a104..2efa208a 100644 --- a/docs/frameworks/preact.md +++ b/docs/frameworks/preact.md @@ -157,5 +157,3 @@ const updateServiceWorker = useRegisterSW({ ``` The interval must be in milliseconds, in the example above it is configured to check the service worker every hour. - - diff --git a/docs/frameworks/react.md b/docs/frameworks/react.md index e6ca84e4..6502c8c7 100644 --- a/docs/frameworks/react.md +++ b/docs/frameworks/react.md @@ -158,5 +158,3 @@ const updateServiceWorker = useRegisterSW({ ``` The interval must be in milliseconds, in the example above it is configured to check the service worker every hour. - - diff --git a/docs/frameworks/solidjs.md b/docs/frameworks/solidjs.md index cea8797e..93256003 100644 --- a/docs/frameworks/solidjs.md +++ b/docs/frameworks/solidjs.md @@ -162,5 +162,3 @@ const updateServiceWorker = useRegisterSW({ ``` The interval must be in milliseconds, in the example above it is configured to check the service worker every hour. - - diff --git a/docs/frameworks/svelte.md b/docs/frameworks/svelte.md index 7b043591..dcd7a676 100644 --- a/docs/frameworks/svelte.md +++ b/docs/frameworks/svelte.md @@ -150,6 +150,3 @@ const updateServiceWorker = useRegisterSW({ ``` The interval must be in milliseconds, in the example above it is configured to check the service worker every hour. - - - diff --git a/docs/frameworks/vue.md b/docs/frameworks/vue.md index dc37ccfe..68fc2046 100644 --- a/docs/frameworks/vue.md +++ b/docs/frameworks/vue.md @@ -140,8 +140,6 @@ const updateServiceWorker = useRegisterSW({ The interval must be in milliseconds, in the example above it is configured to check the service worker every hour. - - ## Vue 2 Since this plugin only supports `Vue 3`, you cannot use the virtual module `virtual:pwa-register/vue`. @@ -297,5 +295,3 @@ export default { ``` The interval must be in milliseconds, in the example above it is configured to check the service worker every hour. - - diff --git a/docs/guide/development.md b/docs/guide/development.md index 8555ebeb..4cba2e00 100644 --- a/docs/guide/development.md +++ b/docs/guide/development.md @@ -191,10 +191,6 @@ if ('serviceWorker' in navigator) { } ``` -When you change your service worker source code, `Vite` will force a full reload, since we're using `workbox-window` to register it (by default, you can register it manually) you may have some problems with the service worker events. - - - ## Example You can find an example here: [vue-router](https://github.com/antfu/vite-plugin-pwa/tree/main/examples/vue-router). diff --git a/docs/guide/periodic-sw-updates.md b/docs/guide/periodic-sw-updates.md index d12aeb8b..0f94b997 100644 --- a/docs/guide/periodic-sw-updates.md +++ b/docs/guide/periodic-sw-updates.md @@ -56,8 +56,11 @@ const updateSW = registerSW({ return const resp = await fetch(swUrl, { - 'cache': 'no-store', - 'cache-control': 'no-cache' + cache: 'no-store', + headers: { + 'cache': 'no-store', + 'cache-control': 'no-cache', + }, }) if (resp?.status === 200) @@ -67,5 +70,3 @@ const updateSW = registerSW({ }) ``` ::: - - diff --git a/src/client/build/register.ts b/src/client/build/register.ts index 30bdcad1..47bae3ea 100644 --- a/src/client/build/register.ts +++ b/src/client/build/register.ts @@ -29,43 +29,38 @@ export function registerSW(options: RegisterSWOptions = {}) { let registerPromise: Promise let sendSkipWaitingMessage: () => Promise | undefined - const updateServiceWorker = async (reloadPage = true) => { + const updateServiceWorker = async (_reloadPage = true) => { await registerPromise if (!auto) { - // Assuming the user accepted the update, set up a listener - // that will reload the page as soon as the previously waiting - // service worker has taken control. - if (reloadPage) { - wb?.addEventListener('controlling', (event) => { - if (event.isUpdate) - window.location.reload() - }) - } - await sendSkipWaitingMessage?.() } } async function register() { if ('serviceWorker' in navigator) { - const { Workbox, messageSW } = await import('workbox-window') + const { Workbox } = await import('workbox-window') + // __SW__, __SCOPE__ and __TYPE__ will be replaced by virtual module + wb = new Workbox('__SW__', { scope: '__SCOPE__', type: '__TYPE__' }) sendSkipWaitingMessage = async () => { if (registration && registration.waiting) { // Send a message to the waiting service worker, // instructing it to activate. // Note: for this to work, you have to add a message // listener in your service worker. See below. - await messageSW(registration.waiting, { type: 'SKIP_WAITING' }) + await wb?.messageSkipWaiting() } } - // __SW__, __SCOPE__ and __TYPE__ will be replaced by virtual module - wb = new Workbox('__SW__', { scope: '__SCOPE__', type: '__TYPE__' }) wb.addEventListener('activated', (event) => { - // this will only controls the offline request. + // This will only controls the offline request. // event.isUpdate will be true if another version of the service // worker was controlling the page when this version was registered. - if (event.isUpdate) + // When using multiple clients, if the client that fires the update is not the current one, + // workbox-window will fire this event with isUpdate=undefined and isExternal=true + // we only need to check this case and force reloading the page, otherwise use current logic + if (!event.isUpdate && event.isExternal) + window.location.reload() + else if (event.isUpdate) auto && window.location.reload() else if (!autoDestroy) onOfflineReady?.() @@ -81,6 +76,14 @@ export function registerSW(options: RegisterSWOptions = {}) { // Assumes your app has some sort of prompt UI element // that a user can either accept or reject. + // Assuming the user accepted the update, set up a listener + // that will reload the page as soon as the previously waiting + // service worker has taken control. + wb?.addEventListener('controlling', (event) => { + if (event.isUpdate) + window.location.reload() + }) + onNeedRefresh?.() }