progressive-web-appsservice-workerservice-worker-events

How to check for installed web app (PWA) updates when using precache method


I have a Progressive Web App in which the service worker is configured as shown below. I follow precache method. Every files will be cached first and the requests will be served from the cache. If there is no match in local cache, then request is served over network. If everything fails an offline/error page is shown. Everything works fine. But I am stuck at giving an update to the index.html file.

const pb_cache = "cv1";
const assets = [
    "./manifest.json",
    "./index.html",
    "./offline.html",
]

self.addEventListener("install", installEvent => {
  installEvent.waitUntil(
    caches.open(pb_cache)
    .then((cache) => {
      return cache.addAll(assets)
      .then(() => {
        return self.skipWaiting(); //To forces the waiting service worker to become the active service worker
      })
    })
  );
});

self.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.match(event.request).then(function(response) {
      if (response) {
        return response;
      }
      return fetch(event.request).then(function(response) {
        if (response.status === 404) {
          return caches.match('/offline.html');
        }
        return response
      });
    }).catch(function() {
      return caches.match('/offline.html');
    })
  );
});

Scenario I have installed the web app to my android phone. Everything is cached and works fine. I need to make changes to the index.html file. So i have added a few tweaks to the file and updated the website. But since the web app installed in android serves local cache, the change in website is not reflected. So I need a mechanism to check for update. What parameter or what thing should I check for update ? I have read many documents related to this and I am not able to grasp the content.

One thing I know is that I have to check for update somewhere in service worker and add it to cache when found in network. I don't know which event or what criteria to check for.


Solution

  • The "manual" way to do this would be to include something like

    // VERSION: 1
    

    at the top of your service worker file, and remember to change that number whenever you make any change to an asset that you're caching during install. The updated version number will result in the automatic service worker update check indicating that there's something new, which will in turn trigger the install handler in your updated service worker file to fire again. All of your precached assets will be added to the cache again at this point.

    After some clarification in the comments, I believe that using cache.addAll() inside of your install handler might be problematic, because you don't have control over your Cache-Control headers, and cache.addAll() will go to the HTTP cache before going to the network. Here's an alternative install handler that will work around this problem by passing in Request objects with the appropriate cache property, instead of passing in URL strings:

    self.addEventListener("install", installEvent => {
      const cacheBypassRequests = assets.map(
        (url) => new Request(url, {cache: 'reload'});
    
      installEvent.waitUntil(
        caches.open(pb_cache)
        .then((cache) => {
          return cache.addAll(cacheBypassRequests)
          .then(() => {
            return self.skipWaiting();
          })
        })
      );
    });
    

    This is obviously error-prone, as you might forget to bump that value when you make a small tweak to one of your assets.

    A somewhat more robust way of doing this is to add a step to a build process for your web app that will update your service worker file's version number each time you redeploy.

    A more production-ready approach is to use a tool that's geared towards solving this specific use case, like workbox-precaching along with the node, webpack, or CLI build interfaces. That will take care of automatically generating a hash of each asset that you want to precache, triggering a new installation whenever one of them changes, and only re-downloading the updated assets.