diff --git a/src/routes/_pages/settings/index.html b/src/routes/_pages/settings/index.html
index 45503ed0..02a30457 100644
--- a/src/routes/_pages/settings/index.html
+++ b/src/routes/_pages/settings/index.html
@@ -36,7 +36,7 @@
methods: {
reload (event) {
event.preventDefault()
- document.location.reload(true)
+ location.reload()
}
}
}
diff --git a/src/routes/_utils/serviceWorkerClient.js b/src/routes/_utils/serviceWorkerClient.js
index d846f083..aed0689f 100644
--- a/src/routes/_utils/serviceWorkerClient.js
+++ b/src/routes/_utils/serviceWorkerClient.js
@@ -1,17 +1,81 @@
import { snackbar } from '../_components/snackbar/snackbar'
-function onUpdateFound (registration) {
- const newWorker = registration.installing
+// A lot of this code is borrowed from https://github.com/GoogleChromeLabs/squoosh/blob/53b46f8/src/lib/offliner.ts
+// Service Workers are hard!
- newWorker.addEventListener('statechange', async () => {
- if (newWorker.state === 'installed' && navigator.serviceWorker.controller) {
- snackbar.announce('App update available.', 'Reload', () => document.location.reload(true))
+// Tell the service worker to skip waiting
+async function skipWaiting () {
+ const reg = await navigator.serviceWorker.getRegistration()
+ if (!reg || !reg.waiting) {
+ return
+ }
+ reg.waiting.postMessage('skip-waiting')
+}
+
+// Wait for an installing worker
+async function installingWorker (reg) {
+ if (reg.installing) {
+ return reg.installing
+ }
+ return new Promise((resolve) => {
+ reg.addEventListener(
+ 'updatefound',
+ () => resolve(reg.installing),
+ { once: true }
+ )
+ })
+}
+
+// Wait a service worker to become waiting
+async function updateReady (reg) {
+ if (reg.waiting) {
+ return
+ }
+ const installing = await installingWorker(reg)
+ return new Promise((resolve) => {
+ const listener = () => {
+ if (installing.state === 'installed') {
+ installing.removeEventListener('statechange', listener)
+ resolve()
+ }
}
+ installing.addEventListener('statechange', listener)
})
}
-if ('serviceWorker' in navigator) {
- navigator.serviceWorker.register('/service-worker.js').then(registration => {
- registration.addEventListener('updatefound', () => onUpdateFound(registration))
- })
-}
+(async () => {
+ if ('serviceWorker' in navigator) {
+ navigator.serviceWorker.register('/service-worker.js')
+
+ const hasController = !!navigator.serviceWorker.controller
+
+ navigator.serviceWorker.addEventListener('controllerchange', () => {
+ if (!hasController) { // first install
+ return
+ }
+
+ location.reload()
+ })
+
+ // If we don't have a controller, we don't need to check for updates – we've just loaded from the
+ // network.
+ if (!hasController) {
+ return
+ }
+
+ const reg = await navigator.serviceWorker.getRegistration()
+ if (!reg) { // SW not registered yet
+ return
+ }
+
+ // Look for updates
+ await updateReady(reg)
+
+ // Ask the user if they want to update.
+ snackbar.announce('App update available.', 'Reload', () => {
+ // Tell the waiting worker to activate, this will change the controller and cause a reload (see
+ // 'controllerchange')
+ /* no await */ skipWaiting()
+ })
+ }
+})()
diff --git a/src/service-worker.js b/src/service-worker.js
index d2b44488..d3716fbc 100644
--- a/src/service-worker.js
+++ b/src/service-worker.js
@@ -35,7 +35,6 @@ self.addEventListener('install', event => {
caches.open(WEBPACK_ASSETS).then(cache => cache.addAll(webpackAssets)),
caches.open(ASSETS).then(cache => cache.addAll(assets))
])
- self.skipWaiting()
})())
})
@@ -243,3 +242,11 @@ self.addEventListener('notificationclick', event => {
}
})())
})
+
+self.addEventListener('message', (event) => {
+ switch (event.data) {
+ case 'skip-waiting':
+ self.skipWaiting()
+ break
+ }
+})