How to refresh the page after a ServiceWorker upda

2019-03-11 00:26发布

问题:

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. :/

回答1:

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



回答2:

External: stop and unregister a service worker using chrome://serviceworker-internals/

Internal from service worker itself: https://developer.mozilla.org/en-US/docs/Web/API/Clients/claim and https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerGlobalScope/skipWaiting



回答3:

In Chrome Canary you can do all sort of Service Worker profiling and management like unregister, clear in the Applications Tab:

Pair that with chrome://devices/ to debug with your physical device.