9

I have a website which has a service worker like:

// Import a script from another domain
importScripts('https://example.com/script.js')

Suppose that script.js is updated with some new code and the service worker is activated due to a push event (the user is the meantime has not visited my website again).

Does importScripts checks for updates each time the service worker is activated or it downloads the script.js just once when the service worker is first installed?

Is there any way to have the service worker code (and in particular the imported scripts) refreshed each time the service worker receives a push message?

collimarco
  • 34,231
  • 36
  • 108
  • 142
  • I wrote a [blog post](http://blog.pushpad.xyz/2017/05/update-the-service-worker-and-the-scripts-imported-with-importscripts/) with some tips. – collimarco May 01 '17 at 14:07

3 Answers3

5

From the Service Workers specification, scripts imported via importScripts are stored in a map when the Service Worker is installed/updated and are then reused until a new update. There's a discussion on GitHub with more details.

I can't think of a way to reload the imported scripts when a service worker receives a push message. What is your use case?

Marco Castelluccio
  • 10,152
  • 2
  • 33
  • 48
  • Yes, unfortunately there's no way to update the imported scripts. The only workaround is to add dummy content to the main service worker code. This is [the use case](http://blog.pushpad.xyz/2016/07/service-worker-importscripts-never-updates-scripts/). – collimarco Jul 09 '16 at 12:16
  • Yes, but even then you can't force it to be updated when a push message arrives, can you? A less ugly workaround is to use "importedScriptName-" + hash of the contents of the imported script + ".js" as the name of the imported script. This way the content of the service worker will change when the imported script changes. – Marco Castelluccio Jul 09 '16 at 15:29
  • Yes, when a push arrives it checks for updates (I think if the last check for updates was more than 24 hours before). You can't easily generate an hash (the imported script belongs to a different domain...) and people may have static websites (or assets). I've also replied to you on the blog – collimarco Jul 10 '16 at 07:27
  • Oh, your clients write the service worker, I thought it was a solution similar to other services (like OneSignal), where you provide the service worker. Btw, I replied on the blog. The dummy content solution requires people to know when the imported scripts have changed (since they need to add the dummy content when the content has changed), doesn't it? The hash solution is instead automatic. The generation is made server-side, so it doesn't matter that they belong to a different domain. – Marco Castelluccio Jul 10 '16 at 09:50
  • Yes, it's like OneSignal: I think they have the exact same problem if they update their scripts. And IMHO it's a problem generating the hash server side because 1. you generate the hash of the included scripts every time 2. otherwise you should also implement a cache system in order to avoid making HTTP requests server side and generating the hash every time – collimarco Jul 11 '16 at 09:51
  • As far as I remember, with OneSignal they write the service worker, the clients don't (which is different than your case). Note that I'm not saying that the hash solution is great, I'm saying that it's better than adding dummy content. – Marco Castelluccio Jul 11 '16 at 10:02
  • No, it's not different from my case. OneSignal behaves exactly like Pushpad for this aspect – collimarco Jul 11 '16 at 13:02
4

It's possible to force the browser to revalidate/check whether code included via importScripts() has been updated by dynamically generating the service worker URL—if this changes every hour, then the browser will download and install a "new" service worker, including all imported scripts.

The following code will cause the browser to check all dependencies every hour:

const MAXAGE = 3600; // seconds until recheck
const URL = `/sw.js?q=${Math.floor(Date.now() / (MAXAGE * 1000))}`;
navigator.serviceWorker.register(URL);

Demo — open JS console and click around; you should see the imported script reloaded every 10 seconds.

(This doesn't completely solve your problem (the service worker is only updated when the user visits the page, not when the push notification is received) but it might be sufficient.)

mjs
  • 63,493
  • 27
  • 91
  • 122
  • A more comprehensive answer to the question of how to deploy updates to service workers: http://stackoverflow.com/a/43471531 – mjs Apr 18 '17 at 12:01
  • This no longer works on Chrome 71+: https://www.chromestatus.com/feature/5748516353736704. – ofavre Jul 02 '19 at 12:44
1

From chrome 68, this can be done by setting {updateViaCache: 'none'} while registering service worker. It doesn't use cache then for contents of imported files

See full reference about definition at w3 and Chrome Updates

Prashant Singh
  • 3,725
  • 12
  • 62
  • 106