Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: prompt for update logic #428

Merged
merged 2 commits into from Jan 3, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
107 changes: 60 additions & 47 deletions src/client/build/register.ts
Expand Up @@ -25,7 +25,6 @@ export function registerSW(options: RegisterSWOptions = {}) {
} = options

let wb: import('workbox-window').Workbox | undefined
let registration: ServiceWorkerRegistration | undefined
let registerPromise: Promise<void>
let sendSkipWaitingMessage: () => Promise<void> | undefined

Expand All @@ -42,61 +41,75 @@ export function registerSW(options: RegisterSWOptions = {}) {
// __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 wb?.messageSkipWaiting()
}
// 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 wb?.messageSkipWaiting()
}

wb.addEventListener('activated', (event) => {
// 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.
// 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?.()
})

if (!auto) {
const showSkipWaitingPrompt = () => {
// \`event.wasWaitingBeforeRegister\` will be false if this is
// the first time the updated service worker is waiting.
// When \`event.wasWaitingBeforeRegister\` is true, a previously
// updated service worker is still waiting.
// You may want to customize the UI prompt accordingly.

// 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)
if (!autoDestroy) {
if (auto) {
wb.addEventListener('activated', (event) => {
if (event.isUpdate || event.isExternal)
window.location.reload()
})

onNeedRefresh?.()
wb.addEventListener('installed', (event) => {
if (!event.isUpdate) {
onOfflineReady?.()
}
});
}
else {
let onNeedRefreshCalled = false
const showSkipWaitingPrompt = () => {
onNeedRefreshCalled = true
// \`event.wasWaitingBeforeRegister\` will be false if this is
// the first time the updated service worker is waiting.
// When \`event.wasWaitingBeforeRegister\` is true, a previously
// updated service worker is still waiting.
// You may want to customize the UI prompt accordingly.

// Add an event listener to detect when the registered
// service worker has installed but is waiting to activate.
wb.addEventListener('waiting', showSkipWaitingPrompt)
// @ts-expect-error event listener provided by workbox-window
wb.addEventListener('externalwaiting', showSkipWaitingPrompt)
// 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?.()
}
wb.addEventListener('installed', (event) => {
if (typeof event.isUpdate === 'undefined') {
if (typeof event.isExternal !== 'undefined') {
if (event.isExternal)
showSkipWaitingPrompt()
else
!onNeedRefreshCalled && onOfflineReady?.()
}
else {
if (event.isExternal)
window.location.reload()
else
!onNeedRefreshCalled && onOfflineReady?.()
}
}
else if (!event.isUpdate) {
onOfflineReady?.()
}
});
// Add an event listener to detect when the registered
// service worker has installed but is waiting to activate.
wb.addEventListener('waiting', showSkipWaitingPrompt)
// @ts-expect-error event listener provided by workbox-window
wb.addEventListener('externalwaiting', showSkipWaitingPrompt)
}
}

// register the service worker
wb.register({ immediate }).then((r) => {
registration = r
if (onRegisteredSW)
onRegisteredSW('__SW__', r)
else
Expand Down