Skip to content
This repository has been archived by the owner on Dec 29, 2022. It is now read-only.

How to update files cached by service worker? #1046

Open
davidmaxwaterman opened this issue Jul 11, 2017 · 7 comments
Open

How to update files cached by service worker? #1046

davidmaxwaterman opened this issue Jul 11, 2017 · 7 comments

Comments

@davidmaxwaterman
Copy link
Contributor

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
Copy link
Contributor Author

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.

@keanulee
Copy link
Contributor

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

@davidmaxwaterman
Copy link
Contributor Author

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.

@keanulee
Copy link
Contributor

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

@chwzr
Copy link

chwzr commented Jan 2, 2018

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")

@keanulee
Copy link
Contributor

keanulee commented Jan 2, 2018

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.');
              }
            };
          }
        });
      }

@chwzr
Copy link

chwzr commented Jan 2, 2018

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!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants