polymer-starter-kit icon indicating copy to clipboard operation
polymer-starter-kit copied to clipboard

How to update files cached by service worker?

Open davidmaxwaterman opened this issue 7 years ago • 7 comments

I have an app that was based on psk, but I am having trouble updating the app when I have deployed new source files. I have it installed on my Nexus 5 and the only way I seem to force it to update is by going to chrome://serviceworker-internals and unregistering the SW. I have tried reloading the app by dragging down and getting the reload icon, but that doesn't seem to do the trick. Any pointers would be welcome.

davidmaxwaterman avatar Jul 11 '17 21:07 davidmaxwaterman

Oh, I should also point out that, from what I read, the service worker would first serve the cached files and get new ones from the network, then the cache would be updated for the next load...but that doesn't seem to be the case.

davidmaxwaterman avatar Jul 11 '17 21:07 davidmaxwaterman

polymer build internally uses sw-precache to generate a service worker which contains hashes of the output files, for example:

var precacheConfig = [["index.html","97f753b9a712d6873e321c7f29adf9ad"], /* ... */];

This hash changes when the source changes, so the resulting SW will be byte-different than the previous SW. When this happens, the SW will update the precached assets and they will be available on the next page load (thus why some sites use a "refresh to update" prompt).

Like other files, the SW script is subject to disk-caching by the browser. So, it's recommended that you set a Cache-Control: max-age=0 HTTP header on service-worker.js (though not required, if you're okay will serving a stale site).

Further reading: https://developers.google.com/web/fundamentals/instant-and-offline/service-worker/lifecycle

keanulee avatar Aug 15 '17 00:08 keanulee

It would be really awesome if the PSK were to include code that shows an implementation of a 'new version available. Update [yes][not]' toast, and associated sw code.

davidmaxwaterman avatar Sep 17 '17 11:09 davidmaxwaterman

For reference, here's how the Polymer docs site creates that toast: https://github.com/Polymer/docs/blob/master/app/js/app.js#L130

keanulee avatar Sep 18 '17 00:09 keanulee

The implementation in the link does not work for the PSK..

I've copied the code and replaced the service worker registration lines in index.html with the ones from the link, and replaced the toast messages and console.log these instead, since there is no material toast in the psk...:

if ('serviceWorker' in navigator) {
  console.log("Browser Supports Service Worker");
  window.addEventListener('load', function() {
    navigator.serviceWorker.register('service-worker.js', {
     scope: Polymer.rootPath,
   }).then(function(registration) {
      registration.onupdatefound = function() {
        // The updatefound event implies that registration.installing is set; see
        // https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#service-worker-container-updatefound-event
        const installingWorker = registration.installing;
        installingWorker.onstatechange = function() {
          switch (installingWorker.state) {
            case 'installed':                    
              if (!navigator.serviceWorker.controller) {
                //window.showToast('Service Worker installed!...
                console.log("Service Worker is installed!");
              }
              break;
              
            case 'redundant':
              console.log("The installing service worker became redundant.");
          }
        };
      };
    }).catch(function(e) {
      console.log("Service worker registration failed:", e);
    });
    // Check to see if the service worker controlling the page at initial load
    // has become redundant, since this implies there's a new service worker with fresh content.
    if (navigator.serviceWorker.controller) {
      navigator.serviceWorker.controller.onstatechange = function(event) {
        if (event.target.state === 'redundant') {
          console.log("Service Worker is redundant. New content is available, refresh to see the changes!")
          // window.showToast('Site updated. Refresh this page to see the latest content.');
        }
      };
    }
  });
}

I can do everything (change e.g. service worker cache id and rebuild it), all the messages don't log but the first ("Browser Supports Service Worker"). But when i hit update service worker in dev tools it is logging...("Service Worker is installed")

chwzr avatar Jan 02 '18 20:01 chwzr

There are syntax errors in that code snippet, which are apparent if you use GitHub markdown code blocks:

      if ('serviceWorker' in navigator) {
        console.log("Browser Supports Service Worker");
        window.addEventListener('load', function() {
          navigator.serviceWorker.register('service-worker.js', {
           scope: Polymer.rootPath,
         }).then(function(registration) {
            registration.onupdatefound = function() {
              // The updatefound event implies that registration.installing is set; see
              // https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#service-worker-container-updatefound-event
              const installingWorker = registration.installing;
              installingWorker.onstatechange = function() {
                switch (installingWorker.state) {
                  case 'installed':                    
                    if (!navigator.serviceWorker.controller) {
                      //window.showToast('Service Worker installed! Pages you view are cached for offline use.');
                      console.log("Service Worker is installed!
                    break;

                  case 'redundant':
                    console.log("The installing service worker became redundant.");
                }
              };
            };
          }).catch(function(e) {
            console.log("Service worker registration failed:", e);
          });

          // Check to see if the service worker controlling the page at initial load
          // has become redundant, since this implies there's a new service worker with fresh content.
          if (navigator.serviceWorker.controller) {
            navigator.serviceWorker.controller.onstatechange = function(event) {
              if (event.target.state === 'redundant') {
                console.log("Service Worker is redundant. New content is available, refresh to see the changes!")
                // window.showToast('Site updated. Refresh this page to see the latest content.');
              }
            };
          }
        });
      }

keanulee avatar Jan 02 '18 20:01 keanulee

Sorry, updated the code block, it was a copy paste error. Even without the mistakes, the behaviours is like described above.

But i've found out that its not an issue with the service worker registering: For those hosting on Firebase, the Cache-Control header cache-control:max-age=3600is set to one hour, so for apps in development you can use this snippet inside your firebase.json's hosting Object to disable caching for the service worker at all:

    "headers": [{
      "source" : "service-worker.js",
      "headers" : [{
        "key" : "Cache-Control",
        "value" : "max-age=0"
      }]
    }]

In a production environment, however, one should rethink the importance of the app's up-to-dateness for the sake of LIGHTSPEED page load times and adjust it back to one hour ;-)

thx @keanulee for helping anyway, not learned markdown so far!

chwzr avatar Jan 02 '18 21:01 chwzr