React
You can use the built-in Vite
virtual module virtual:pwa-register/react
for React
which will return useState
stateful values (useState<boolean>
) for offlineReady
and needRefresh
.
WARNING
You will need to add workbox-window
as a dev
dependency to your Vite
project.
Type declarations
TIP
If your TypeScript build step or IDE complain about not being able to find modules or type definitions on imports, add the following to the compilerOptions.types
array of your tsconfig.json
:
{
"compilerOptions": {
"types": [
"vite-plugin-pwa/client"
]
}
}
Or you can add the following reference in any of your d.ts
files (for example, in vite-env.d.ts
or global.d.ts
):
/// <reference types="vite-plugin-pwa/client" />
From version 0.14.5
you can also use types definition for react instead of vite-plugin-pwa/client
, you can use:
{
"compilerOptions": {
"types": [
"vite-plugin-pwa/react"
]
}
}
Or you can add the following reference in any of your d.ts
files (for example, in vite-env.d.ts
or global.d.ts
):
/// <reference types="vite-plugin-pwa/react" />
declare module 'virtual:pwa-register/react' {
import type { Dispatch, SetStateAction } from 'react'
import type { RegisterSWOptions } from 'vite-plugin-pwa/types'
export type { RegisterSWOptions }
export function useRegisterSW(options?: RegisterSWOptions): {
needRefresh: [boolean, Dispatch<SetStateAction<boolean>>]
offlineReady: [boolean, Dispatch<SetStateAction<boolean>>]
updateServiceWorker: (reloadPage?: boolean) => Promise<void>
}
}
Prompt for update
WARNING
The options provided to hooks are not reactive. Therefore, the callback references will be the first rendered options instead of the latest hook’s options. If you are doing complex logic with state changes, you will need to provide a stable reference function.
You can use this ReloadPrompt.tsx
component:
ReloadPrompt.tsx
import React from 'react'
import './ReloadPrompt.css'
import { useRegisterSW } from 'virtual:pwa-register/react'
function ReloadPrompt() {
const {
offlineReady: [offlineReady, setOfflineReady],
needRefresh: [needRefresh, setNeedRefresh],
updateServiceWorker,
} = useRegisterSW({
onRegistered(r) {
// eslint-disable-next-line prefer-template
console.log('SW Registered: ' + r)
},
onRegisterError(error) {
console.log('SW registration error', error)
},
})
const close = () => {
setOfflineReady(false)
setNeedRefresh(false)
}
return (
<div className="ReloadPrompt-container">
{ (offlineReady || needRefresh)
&& <div className="ReloadPrompt-toast">
<div className="ReloadPrompt-message">
{ offlineReady
? <span>App ready to work offline</span>
: <span>New content available, click on reload button to update.</span>
}
</div>
{ needRefresh && <button className="ReloadPrompt-toast-button" onClick={() => updateServiceWorker(true)}>Reload</button> }
<button className="ReloadPrompt-toast-button" onClick={() => close()}>Close</button>
</div>
}
</div>
)
}
export default ReloadPrompt
and its corresponding ReloadPrompt.css
styles file:
ReloadPrompt.css
.ReloadPrompt-container {
padding: 0;
margin: 0;
width: 0;
height: 0;
}
.ReloadPrompt-toast {
position: fixed;
right: 0;
bottom: 0;
margin: 16px;
padding: 12px;
border: 1px solid #8885;
border-radius: 4px;
z-index: 1;
text-align: left;
box-shadow: 3px 4px 5px 0 #8885;
background-color: white;
}
.ReloadPrompt-toast-message {
margin-bottom: 8px;
}
.ReloadPrompt-toast-button {
border: 1px solid #8885;
outline: none;
margin-right: 5px;
border-radius: 2px;
padding: 3px 10px;
}
Periodic SW Updates
As explained in Periodic Service Worker Updates, you can use this code to configure this behavior on your application with the virtual module virtual:pwa-register/react
:
import { useRegisterSW } from 'virtual:pwa-register/react'
const intervalMS = 60 * 60 * 1000
const updateServiceWorker = useRegisterSW({
onRegistered(r) {
r && setInterval(() => {
r.update()
}, intervalMS)
}
})
The interval must be in milliseconds, in the example above it is configured to check the service worker every hour.
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).