5

I have been toying around with service workers and sw-toolbox. Both are great methods but seems to have their weaknesses.

My project started out using Google's method of service workers (link). The way I see this is that you have to manually update the version number for cache busting. I could be wrong also but I don't think the pages that the users has visited will not be cached.

Compared to the sw-toolbox method, all I need to add is the following code:

self.toolbox.router.default = self.toolbox.networkFirst;

self.toolbox.router.get('/(.*)', function (req, vals, opts) {
    return self.toolbox.networkFirst(req, vals, opts)
        .catch(function (error) {
            if (req.method === 'GET' && req.headers.get('accept').includes('text/html')) {
                return self.toolbox.cacheOnly(new Request(OFFLINE_URL), vals, opts);
            }
            throw error;
        });
});

Then the problem of caching pages will be solved. Here is my issue: after applying the sw-toolbox to my project, the old service worker doesn't get cleared or replaced by the new one unless I go to the dev tools to clear it.

Any ideas how to get around this?

oninross
  • 989
  • 6
  • 23
  • You are not looking for [ServiceWorkerRegistration.update()](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration/update)? – Jeroen Heier Jun 21 '17 at 03:58
  • But by including this on the file, it will force update the SW every time right? – oninross Jun 21 '17 at 08:14
  • @oninross the `update` method will only update the service worker if it has changed (e.i., it is byte-different). This won't necessarily solve your issue though, because updating only installs the new service worker. It still wont activate until the old one is no longer in use, or you use a method like `skipWaiting` (see answer below). – David Jun 21 '17 at 17:14

2 Answers2

7

Here is my issue: after applying the sw-toolbox to my project, the old service worker doesn't get cleared or replaced by the new one unless I go to the dev tools to clear it.

The browser checks for updates to the service worker file every time it requests a resource in the service worker scope. If there is a byte difference in the service worker files, the browser will install the new service worker. You only need to update the service worker manually in dev tools because the app is still running, and the browser does not want to activate a new service worker while the old one is still in use.

If you close all pages associated with the service worker (like a user would when leaving your app), the browser will be able to activate the new service worker the next time your page is opened.

If you want to force the new service worker to take over, you can add self.skipWaiting(); to the install event. Here is some documentation with an example.

You can learn just about everything you need to know about the service worker's life cycle from this post by Jake Arichbald.

As far as caching & cache management goes, tools like sw-toolbox will handle cache busting for you. And actually, Workbox is a new tool that is meant to replace sw-toolbox & sw-precache. It will also handle cache busting and cache management (by comparing file hashes & setting/tracking resource expiration dates).

Generally speaking, you should always use a tool like Workbox to write your service workers. Writing them by hand is error prone and you are likely to miss corner cases.

Hope that helps.

P.S. If you end up not using skipWaiting and instead only updating when the page is closed & re-opened by a user, you can still enable automatic updating for development. In Chrome's dev tools, Application > Service Workers has an Update on reload option to automatically update the service worker.

David
  • 2,846
  • 3
  • 22
  • 34
1

I don't know if sw_toolbox has cache busting built in. Typically when you change the service worker and need to purge the previous version's cache you should do that with in the activate event handler.

The best practice here is to name your caches with the sw version number included. Here is some example code from an online course I have on service worker caching that might get you started:

self.addEventListener("activate", event => {

console.log("service worker activated");

//on activate
event.waitUntil(caches.keys()
    .then(function (cacheNames) {

        cacheNames.forEach(function (value) {

            if (value.indexOf(config.version) < 0) {

                caches.delete(value);

            }

        });

        return;

    })
);

});

Chris Love
  • 3,740
  • 1
  • 19
  • 16