How to force service worker to update?
Asked Answered
H

6

28

I'm using sw-precache to generate my service work with Polymer CLI build process, so it's intended to update the hash of updated files to signal a need to update the cache. But my updated content is not being replaced in cache, so it's getting an old version if I refresh with ctrl+r but the new version if I refresh with ctrl+shift+r. A reason for that can be that my service worker is not being updated.

This doc states that

If there is even a byte's difference in the service worker file compared to what it currently has, it considers it new.

, but what if my new service worker didn't change a byte? (as it happens if just one hash has changed). How to configure the sw-precache to update the service work at every new request?

Harlanharland answered 27/1, 2017 at 21:14 Comment(4)
Have you looked at this? developer.mozilla.org/en-US/docs/Web/API/… And please confirm that hashes are working properly: meaning that after changing an cached asset file, it reflects it to service worker content. In other words hash value changes in the service worker. Beware that SW does not care nor can check content or version of the assets files. Only thing can trigger it to update is it's own content. So, changes in asset files should reflect to their references in SW. e.g. /style.css?{hash-of-the-file}Jeer
I'm sure that the hash is changing. The 'skipWaiting' I didn't test, I've read the documentation and what I understood is that this is intended to force an update without reloading the page. My case seems to be different as the lifecycle of a service worker ends when there's another one waiting and the page is reloaded, without the need of 'skipWaiting'.Harlanharland
That is simply not true. see the documentation ...the new version is installed in the background, but not yet activated. It is only activated when there are no longer any pages loaded that are still using the old service worker. As soon as there are no more such pages still loaded, the new service worker activates.Jeer
Hey just a heads-up: there is an another question which I have just replied. There might be useful information for you too since it is very similar to yours.Jeer
W
21

As the previous answers stated, there is a 1 day (24hr) built-in limit for the browser to look for updates to the service worker, but what you need to be mindful of is you still need to call .update() on your ServiceWorkerRegistration object otherwise the original version of the file will be used.

While testing changes in Chrome, I always right-click on the refresh button and select 'Empty Cache and Hard Reset' (options are available when developer tools are open) when working on my service worker script.

Williwaw answered 29/8, 2017 at 19:35 Comment(4)
Nice Chrome tip, I would never notice.Harlanharland
That's ok in your dev environment, but what if you issue (maybe even multiple) updates to your website within that built-in limit?Baltimore
@CsabaToth I'm not sure what the "right" answer is here, but you might just need to wait for the 24 hour limit. You really have no control over the client's browser. The answer above was just to help during development. Mind you, this answer is over a year old now, conditions may have changed since I posted that.Williwaw
@Williwaw You can explicitly call .update()! But that's ugly.Baltimore
S
14

'sw-precache' has been superseded by Workbox which generates hashes for the files you want to precache and adds those to the source code of your service worker (I don't know if sw-precache works the same way, Jeff's answer suggests it does). If any of the files you want to precache change -- and you re-run your build -- the updated hashes in your service worker are updated which pretty much guarantees the service worker will be "at least one byte different".

When you reload (ctrl-r) or re-visit your app the browser will fetch again the service worker that was registered for it. And, if that service worker has changed, it will be "queued up" to manage the app. But it won't start managing the app until you close all tabs with the app open, and then open a new one.

When you hard refresh (shift-ctrl-r) it’ll always load without a controller which is not the same as using your new service worker.

For testing during development, I use skip waiting in devtools to make the new service worker replace the old one without waiting for me to close all the tabs.

Satterwhite answered 19/10, 2017 at 10:24 Comment(0)
P
11

If one file's hash changes, that's enough to ensure that the service worker JavaScript file generated by sw-precache changes. That, in turn, is enough to trigger the service worker update flow.

If you're not seeing an update flow triggered while testing things out, then it may be due to the service worker JavaScript file being served with HTTP caching headers that cause it to be fetched from the browser's cache rather than the from the network.

See https://mcmap.net/q/168793/-service-worker-javascript-update-frequency-every-24-hours for a discussion of how HTTP caching headers come into play, and the best practices with regards to that.

Provender answered 31/1, 2017 at 16:40 Comment(2)
Well, the first paragraph is something I'd expect, but the practice shows it's not always happening.Baltimore
Is your service worker being cached somewhere along the line? If so, then the browser won't know anything changed. You need to make sure any web caches aren't caching your service worker.Implant
D
4

One option that I have implemented from a UX standpoint is calling the unregister method on your service worker. (https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration/unregister)

Once the unregister process is complete you can:

  1. force the window to refresh (window.location.reload)
  2. Based on your load up process, you can fetch the new service worker which will hopefully cache all your new content.

I have ran into weird issues with the service worker before, so this type of solution allows you to somewhat clear the old cache and refresh the state of your application without forcing users to clear their actual browser cache, while at the same time reloading your application.

EX (How to Unregister):

serviceworker.unregister()
    .then( unregResult => { 
       //You can check if successful with Promise result 'unregResult'
       window.location.reload();
    })
Dominique answered 8/9, 2020 at 15:16 Comment(0)
S
3

Store a version number in service‑worker.js

A one-character change in the controlling service-worker.js will automatically trigger a PWA update. Hence, if you store the version number in a const in this file and change it, an update of the PWA will be triggered.

How the update eventually is handled, is determined by the service-worker.js. Different update strategies may be defined in terms of the size and volatility of the PWA assets.

However, there is one important caveat. Make sure that the browser cache expiry directive set by the .htaccess file on your asset server is set to a really short duration (e.g. hours) or even to none. Failing to do so, will result in the browser not seeing any change for days to come in the manifest.json, nor the service-worker.js.

More details about service worker behaviour are available from Google Web Fundamentals.

Supraorbital answered 24/3, 2021 at 14:43 Comment(0)
S
-4
const messaging = firebase.messaging();
messaging.setBackgroundMessageHandler(function(payload) {

    //Force the Service Worker to Upddate
    self.registration.update();

    const notification = JSON.parse(payload.data.notification);
    return self.registration.showNotification(notification.title, notification);

});
Schiro answered 12/11, 2019 at 10:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.