Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to refresh the page after a ServiceWorker update?

Tags:

I've consulted a lot of resources on Service Workers:

  • Updating your ServiceWorker
  • ServiceWorker: Revolution of the Web Platform
  • Jake Archibald's lovely SVGOMG.

However, I can't for the life of me figure out how to update the page after a new ServiceWorker has been installed. No matter what I do, my page is stuck on an old version, and only a hard refresh (Cmd-Shift-R) will fix it. No combination of 1) closing the tab, 2) closing Chrome, or 3) location.reload(true) will serve the new content.

I have a super simple example app mostly based on SVGOMG. On installation, I cache a bunch of resources using cache.addAll(), and I also do skipWaiting() if the current version's major version number doesn't match the active version's number (based on an IndexedDB lookup):

self.addEventListener('install', function install(event) {   event.waitUntil((async () => {     var activeVersionPromise = localForage.getItem('active-version');     var cache = await caches.open('cache-' + version);     await cache.addAll(staticContent);     var activeVersion = await activeVersionPromise;     if (!activeVersion ||       semver.parse(activeVersion).major === semver.parse(version).major) {       if (self.skipWaiting) { // wrapping in an if while Chrome 40 is still around         self.skipWaiting();       }     }   })()); }); 

I'm using a semver-inspired system where the major version number indicates that the new ServiceWorker can't be hot-swapped for the old one. This works on the ServiceWorker side - a bump from v1.0.0 to v1.0.1 causes the worker to be immediately installed on a refresh, whereas from v1.0.0 to v2.0.0, it waits for the tab to be closed and reopened before being installed.

Back in the main thread, I'm manually updating the ServiceWorker after registration – otherwise the page never even gets the memo that there's a new version of the ServiceWorker available (oddly I found very few mentions of this anywhere in the ServiceWorker literature):

navigator.serviceWorker.register('/sw-bundle.js', {   scope: './' }).then(registration => {   if (typeof registration.update == 'function') {     registration.update();   } }); 

However, the content that gets served to the main thread is always stuck on an old version of the page ("My version is 1.0.0"), regardless of whether I increment the version to 1.0.1 or 2.0.0.

I'm kind of stumped here. I was hoping to find an elegant semver-y solution to ServiceWorker versioning (hence my use of require('./package.json').version), but in my current implementation, the user is perpetually stuck on an old version of the page, unless they hard-refresh or manually clear out all their data. :/

like image 595
nlawson Avatar asked Jan 18 '16 22:01

nlawson


People also ask

How does a service worker work?

Service workers are specialized JavaScript assets that act as proxies between web browsers and web servers. They aim to improve reliability by providing offline access, as well as boost page performance.


1 Answers

Found the issue – you need to avoid any cache headers on the ServiceWorker JS file itself. Setting the cache to max-age=0 immediately solved the problem: https://github.com/nolanlawson/serviceworker-update-demo/pull/1

Cheers to Jake Archibald for setting me straight: https://twitter.com/jaffathecake/status/689214019308224513

like image 75
nlawson Avatar answered Oct 08 '22 11:10

nlawson