I am creating a PWA and I want to prompt user when an updated service worker is available but it get's stuck into waiting phase regardless of whether I call skipWaiting()
or I manually press skipWaiting
in dev console.
The new service worker will get installed only if I first stop the existing service worker.
I tried force installation as well by calling self.skipWaiting()
directly in installation phase but my updated service worker still gets stuck into waiting phase.
This is my setup.
sw.js
// when installing hydrate caches and notify user that reload if required (if any)
self.addEventListener('install', async () => {
// self.skipWaiting();
await hydrateCache();
});
self.addEventListener('message', (message) => {
if (message.data === 'skipWaiting') {
debugger;
self.skipWaiting();
}
});
index.html
navigator.serviceWorker.register('sw.js')
.then(function (reg) {
reg.onupdatefound = function() {
var newServiceWorker = reg.installing;
if (reg.waiting && confirm('Updates are available, Would you like to reload?')) {
newServiceWorker.postMessage('skipWaiting');
}
newServiceWorker.onstatechange = function() {
// for some reason I am not getting waiting state update so I am prompting user
// when client gets installed phase update
if (newServiceWorker.state === 'installed') {
if (confirm('Updates are available, Would you like to reload?')) {
newServiceWorker.postMessage('skipWaiting');
}
}
}
}
navigator.serviceWorker.addEventListener('controllerchange', function() {
window.location.reload();
});
})
.catch(function (err) {
console.error('register err', err);
});
I am expecting that whenever I send skipWaiting
message to service worker it should replace existing serviceWorker, my code does call self.skipWaiting()
but in dev console my updated service worker still stays in waiting phase and even if I manually press skipWaiting
it does not replace the existing service worker.
UPDATE:
so after tinkering with my code I found one interesting thing, something from my 'fetch'
event handler is preventing my updated service worker to get activated even though I called skipWaiting()
call.
This code will not let the new service worker get activated
// intercept fetch requests and responds with cached file if they are available like CDN Files
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request)
.then((response) => {
if (response) {
console.log('Found ', event.request.url, ' in cache');
return response;
}
console.log('fetching', event.request.url, 'from internet');
return fetch(event.request);
})
.catch((err) => {
console.error('fetch error', err);
}),
);
});
If I remove my custom code from the 'fetch'
even handler, my updated service worker will get activated when I call skipWaiting()
. I'm basically not doing anything with my 'fetch'
handler as soon as my worker intercepts a request it'll directly try to get it from internet.
self.addEventListener('fetch', (event) => {
return fetch(event.request);
});