Skip to content

Commit 15532ef

Browse files
Karen BaneyKaren Baney
authored andcommitted
Fix issues with manual update. Add readme that gets copied to installing app
1 parent 7e19893 commit 15532ef

File tree

5 files changed

+53
-29
lines changed

5 files changed

+53
-29
lines changed

generator/template/src/composables/use-service-worker.js

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import { ref } from 'vue'
33

44
export const useServiceWorker = (forceUpdate = false) => {
5-
let registration = null
5+
let wb = null
66
const updateExists = ref(false)
77
const refreshing = ref(false)
88

@@ -13,26 +13,27 @@ export const useServiceWorker = (forceUpdate = false) => {
1313
}
1414

1515
refreshing.value = true
16+
updateExists.value = false
1617
window.location.reload()
1718
}
1819

1920
const refreshApp = () => {
2021
console.log('useServiceWorker: refreshApp called.')
21-
updateExists.value = false
22-
if (registration) {
23-
const swState = registration.waiting.state
24-
if (swState === 'waiting' || swState === 'installed') {
25-
navigator.serviceWorker.controller.postMessage({ type: 'SKIP_WAITING' })
26-
console.log('useServiceWorker: Posted SKIP_WAITING message.')
27-
}
28-
}
22+
wb.addEventListener('controlling', (event) => {
23+
reloadApp()
24+
})
25+
26+
wb.messageSkipWaiting()
2927
}
3028

3129
const updateAvailable = (event) => {
3230
console.log('useServiceWorker: Service worker update available.')
3331
if (event && event.detail) {
34-
registration = event.detail
32+
wb = event.detail
3533
updateExists.value = true
34+
35+
// forceUpdate is used by the app-auto-update component to force the app to activate.
36+
// Recommend only using this on the initial landing page or login page of an application.
3637
if (forceUpdate) {
3738
console.log('useServiceWorker: Forcing service worker update.')
3839
refreshApp()
@@ -43,13 +44,6 @@ export const useServiceWorker = (forceUpdate = false) => {
4344
// listen for service worker updates.
4445
document.addEventListener('swUpdated', updateAvailable, { once: true })
4546

46-
if (navigator.serviceWorker) {
47-
navigator.serviceWorker.addEventListener('controllerchange', () => {
48-
console.log('useServiceWorker: controllerchange called')
49-
reloadApp()
50-
})
51-
}
52-
5347
return {
5448
refreshApp,
5549
updateExists
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Setup
2+
After installing vue-cli-plugin-workbox-pwa, you can complete wiring up the Auto Update and Manual Update features.
3+
4+
## Auto Update
5+
The auto update uses:
6+
1. /components/app-auto-update.vue
7+
2. /composables/use-service-worker.js
8+
3. /service-worker/register-service-worker.js
9+
10+
We recommend only adding the Auto Update to a Login Page or Landing Page. Keep in mind that it automatically activates
11+
the service worker and reloads the page, so if it is added to a page that disrupts the user's work (like a form) it could
12+
cause an annoying user experience.
13+
14+
To use the Auto Update, follow the example /service-worker/auto-update-example.
15+
16+
Note: The auto update only works with the InjectManifest option.
17+
18+
## Manual Update
19+
The manual update uses:
20+
1. /components/app-manual-update.vue
21+
2. /composables/use-service-worker.js
22+
3. /service-worker/register-service-worker.js
23+
24+
The Manual Update can be added to the App.vue. See the example in /service-worker/manual-update-example. This feature prompts
25+
the user with a banner and an update button whenever there is a new version of the service worker available. This allows
26+
the user to be in control of when the update happens, so it doesn't interrupt their work.
27+
28+
Note: The manual update only works with the InjectManifest option.

generator/template/src/service-worker/auto-update-example.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ import AppAutoUpdate from '@/components/app-auto-update.vue'
33
44
export default {
55
// To auto update your PWA when a new service worker is available, just drop in the AppAutoUpdate component
6-
// The ideal use case for this would be on a login page, if your application has one.
6+
// The ideal use case for this would be on a landing page or a login page, if your application has one.
77
// Some things to note:
88
// 1. You really only want to auto update when you are sure there will be no adverse affects to your application, like on a login page.
9-
// 2. If you are making your website PWA accessible, then it's probably safe to add this to App.vue or your home page.
9+
// 2. If you are making your website PWA accessible, then it's probably safe to add this to your home page.
1010
// 3. If you are using advanced features of a PWA, like API caching, offline capabilities, etc. You may not want to use the auto update. Instead,
1111
// use the manual update, which gives the user control.
1212
name: 'auto-update-example',

generator/template/src/service-worker/register-service-worker.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
*/
66
import { Workbox } from 'workbox-window'
77

8+
// Checks for updates every hour. When an update is found, the app-auto-update component and use-service-worker composable
9+
// handles the actual updating.
810
const autoUpdate = async (registration) => {
911
const updateInterval = 1000 * 60 * 60 // 1 hour
1012
// const updateInterval = 1000 * 60 // 1 min // for debugging
@@ -19,11 +21,13 @@
1921
}, updateInterval)
2022
}
2123

22-
const manualUpdateAvailable = (registration) => {
24+
// Emits an event that the use-service-worker composable is listens to. Then the app-manual-update is controlled by
25+
// a property on the composable and prompts the user to update.
26+
const manualUpdateAvailable = (wb) => {
2327
// Wires up an event that we can listen to in the app. Example: listen for available update and prompt user to update.
2428
console.log('sw: manualUpdateAvailable dispatching event')
2529
document.dispatchEvent(
26-
new CustomEvent('swUpdated', { detail: registration }))
30+
new CustomEvent('swUpdated', { detail: wb }))
2731
}
2832

2933
const register = async () => {
@@ -43,7 +47,6 @@
4347
console.log('sw: activated event listener hit.')
4448
if (event.isUpdate) {
4549
// event.isUpdate=true means the service worker was already registered and there is a new version available.
46-
// this only triggers self.skipWaiting. It still doesn't force the app to update. See /composables/use-service-worker.ts for updating app.
4750
wb.messageSkipWaiting()
4851
} else {
4952
// first time use when event.isUpdate = false
@@ -60,9 +63,7 @@
6063
wb.addEventListener('waiting', (event) => {
6164
console.log('sw: waiting event listener hit.')
6265
if (event.isUpdate) {
63-
// Wires up event that is listened to in the use-service-worker composable. The app-manual-update component then
64-
// prompts the user there is an update available to activate.
65-
manualUpdateAvailable(registration)
66+
manualUpdateAvailable(wb)
6667
}
6768
})
6869

@@ -72,7 +73,6 @@
7273

7374
wb.addEventListener('fetch', (event) => {
7475
console.log('sw: fetch event listener hit.')
75-
// wb.messageSkipWaiting() // hack to "unfreeze" stuck service worker
7676
})
7777
}
7878
}

generator/template/src/sw.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,10 @@ registerRoute(
6060

6161
self.addEventListener('message', (event) => {
6262
console.log('sw root: message event listener hit.')
63-
if (event.data && event.data.type === 'SKIP_WAITING') {
64-
self.skipWaiting()
65-
console.log('sw root: message SKIP_WAITING called.')
63+
switch (event.data && event.data.type) {
64+
case 'SKIP_WAITING':
65+
self.skipWaiting()
66+
console.log('sw root: message SKIP_WAITING called.')
67+
break
6668
}
6769
})

0 commit comments

Comments
 (0)