Refresh page on controllerchange in service worker
Solution 1
I would recommend following the example from the sw-precache
demo code.
Here's a very concise, modified version of that example that will force a page reload when there's an update to an already installed service worker. (I'd argue that it might be more user-friendly to display a message on the page asking the user to reload manually, though, so that you don't end up interrupting whatever they were doing on the page.)
navigator.serviceWorker.register('/service-worker.js').then(reg => {
reg.onupdatefound = () => {
const installingWorker = reg.installing;
installingWorker.onstatechange = () => {
if (installingWorker.state === 'installed' &&
navigator.serviceWorker.controller) {
// Preferably, display a message asking the user to reload...
location.reload();
}
};
};
});
Solution 2
After many attempts I come with something like that.
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('sw.js')
.then(function (reg) {
if (!navigator.serviceWorker.controller) {
return
}
reg.addEventListener('updatefound', function () {
const newWorker = reg.installing
newWorker.state
var refreshing
newWorker.addEventListener('statechange', () => {
if (newWorker.state == 'activated') {
if (refreshing) return
window.location.reload()
refreshing = true
}
})
trackInstalling(reg.installing)
})
})
}
It's working. Is there any flaws of that code?
Krystus
Updated on June 06, 2022Comments
-
Krystus almost 2 years
I have a simple service worker with button update when new service worker is in queue. After update I want to make page refresh on controllerchange but nothing happens. All in all service worker is updated live but following that course (https://www.udacity.com/course/offline-web-applications--ud899) they try to add that refresh for some reason.
In js:
const updateButton = document.querySelector('.js-update-btn') if ('serviceWorker' in navigator) { navigator.serviceWorker.register('sw.js') .then(function (reg) { if (!navigator.serviceWorker.controller) { return } if (reg.waiting) { updateReady(reg.waiting) return } if (reg.installing) { trackInstalling(reg.installing) return } reg.addEventListener('updatefound', function () { trackInstalling(reg.installing) }) }) var refreshing navigator.serviceWorker.addEventListener('controllerchange', function () { if (refreshing) return window.location.reload() refreshing = true }) } function updateReady (worker) { updateButton.disabled = false updateButton.addEventListener('click', function () { updateButton.disabled = true worker.postMessage({action: 'skipWaiting'}) }) } function trackInstalling (worker) { worker.addEventListener('statechange', function () { if (worker.state == 'installed') { updateReady(worker) } }) }
In sw.js:
self.addEventListener('message', function (event) { if (event.data.action == 'skipWaiting') { self.skipWaiting() } })
-
piotr_cz almost 4 yearsThis doesn't work when page is refreshed via Ctrl+F5 as navigator.serviceWorker.controller is null in the
installed
phase (but has proper value in 'activated' phase)