service worker removal script, plus documentation in the FAQ (ref. #71)

merge-requests/23/head
Michał 'rysiek' Woźniak 2023-11-03 05:56:52 +00:00
rodzic 05e9d6f2a5
commit 9bb1e4c56f
2 zmienionych plików z 85 dodań i 3 usunięć

Wyświetl plik

@ -65,10 +65,12 @@ More information on the Service Worker API [is available in MDN](https://develop
### How do I update LibResilient's service worker code?
For most use-cases it's enough to deploy the new code and let visitor's browser update the service worker automatically. Browsers of returning visitors will load the new version on the first visit that happens after the cache expires, no longer than 24 hours though (as per Service Workers API). LibResilient *does not* handle requests for the `service-worker.js` script nor any of the loaded plugins: in accordance to the API specification, a service worker cannot handle requests for its own code (this is enforced by the browser itself).
For most use-cases it's enough to deploy the new code and let visitor's browser update the service worker automatically. Browsers of returning visitors will load the new version on the first visit that happens after the cache expires, no longer than 24 hours though (as per Service Workers API). LibResilient *does not* handle requests for the `service-worker.js` script nor for any of the loaded plugins: in accordance to the API specification, a service worker cannot handle requests for its own code (this is enforced by the browser itself).
The update can also be triggered by the [`update()` method of the `ServiceWorkerRegistration`](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration/update) interface, but that too complies with the HTTP caching headers for caching up to 24 hours.
It is not adviseable to change the name of the service worker script after deployment. This can lead to multiple service workers loaded in visitor's clients simultaneously.
When debugging code on a developer machine, you can disable cache in your browser's developer tools, which will make the service worker script load as soon as it changes. Please remember that loading and activating a service worker are two different things! See the answer on debugging service workers lower in this FAQ.
### Can LibResilient's service worker be updated when the original domain is not accessible?
@ -77,7 +79,9 @@ No, it cannot. This is clearly specified in the API. Until the website on the or
In the context of LibResilient, this means that even when LibResilient is deployed on a website, and works as expected (pulling content from alternative endpoints or through alternative transports), as long as the original domain is down it is *impossible* to update the service worker or load new plugins.
It is, however, possible to change LibResilient's configuration (including configuration of already loaded plugins), as `config.json` is not a JavaScript file and therefore it is *not* treated as code by browsers. You can read more on updating LibResilient's configuration during disruption [here](./UPDATING_DURING_DISRUPTION.md).
Please note: if the original domain is hijacked or otehrwise taken over, whoever controls it can deploy their own service worker code that will be loaded by visitor's clients, as long as they use the same path and file name of the service worker script. In a situation where the original domain has been taken over or can be expected to be taken over, it is strongly advised to deploy configuration changes that redirect visitors to a new domain (for example, by using the [`redirect` plugin](../plugins/redirect/)).
It is possible, with some caveats (see below), to change LibResilient's configuration (including configuration of already loaded plugins) even if the original domain is down, as `config.json` is not a JavaScript file and therefore it is *not* treated as code by browsers. You can read more on updating LibResilient's configuration during disruption [here](./UPDATING_DURING_DISRUPTION.md).
### Can LibResilient's plugins be updated, or new plugins loaded, when the original domain is not accessible?
@ -97,11 +101,13 @@ A browser will periodically check if a new version of the registered service wor
So a buggy service worker would be deployed for a given user at least for 24 hours (or longer, if they visit the website less frequently).
You can use the [`remove-service-worker.js` script](../lib/remove-service-worker.js) to remove buggy or misconfigured LibResilient service workers from visitor's clients. To do so, replace the contents of `libresilient.js` and `service-worker.js`, as deployed on your site, with the contents of that script. Visitor's clients will periodically check if a new version of the service worker script is available, and eventually load the self-destructing service worker script. How long it takes depends on how often a given visitor visits your site, though.
However, this only relates to the *code* of the service worker (and in case of LibResilient, the code of the plugins). As discussed above, LibResilient allows for *configuration* updates even if the main website is unreachable for whatever reason. Configuration changes (even during disruption) can *disable* plugins. In other words, in certain situations it might be possible to deploy a configuration-based fix to a problem (either by disabling a problematic plugin, or changing the problematic settings).
### If the original domain is down and the service worker is buggy, how long until it gets automatically removed by the browser?
Eventually the browser will remove a service worker. It is unlcear after how long, exactly, but probably a few weeks. But if the site is not available anyway (for reasons unrelated to the service worker), this does not seem like a serious downside.
Eventually the browser will remove a service worker. It is unlcear after how long, exactly, but probably a few weeks. If the site is not available anyway (for reasons unrelated to the service worker), this does not seem like a serious downside.
If the site is available but the service worker code is buggy for whatever reason, it is possible to remove/update it (see above).

Wyświetl plik

@ -0,0 +1,76 @@
/*
* emergency removal of a mis-configured service worker
*
* this file will un-register the service worker, attempting this both from client-side
* and by way of installing a self-destructing service worker script.
*
* use this file to replace these two LibResilient files as deployed on your site,
* keeping their names, then publish your site as normal:
*
* - service-worker.js
* - libresilient.js
*
* these files are normally distributed in the directory that is parent to the one
* this file is in.
*/
// are we running client-side?
if ('serviceWorker' in navigator) {
// we are. unregister all relevant service workers
console.log('LibResilient [COMMIT_UNKNOWN, client-side] :: emergency service worker removal code started')
navigator.serviceWorker.getRegistrations().then( async (registrations)=>{
console.log(`LibResilient [COMMIT_UNKNOWN, client-side] :: removing ${registrations.length} registrations...`)
for (let registration of registrations) {
let result = await registration.unregister();
if (result === true) {
console.log('LibResilient [COMMIT_UNKNOWN, client-side] :: +-- unregistered a registration')
} else {
console.log('LibResilient [COMMIT_UNKNOWN, client-side] :: +-- failed to unregister a registration')
}
}
});
// otherwise, are we running as a service worker already?
} else if ('registration' in self) {
self.addEventListener('install', () => {
console.log('LibResilient [COMMIT_UNKNOWN, service-worker] :: emergency service worker removal code installed')
// we want this activated immediately;
// this means that we become the service worker immediately
self.skipWaiting();
});
self.addEventListener('activate', () => {
// since we are the service worker, we can just... unregister ourselves
console.log('LibResilient [COMMIT_UNKNOWN, service-worker] :: unregistering the service worker...')
self.registration
.unregister()
.then((unresult)=>{
// was the unregistration a success?
if (unresult) {
// indeed
console.log('LibResilient [COMMIT_UNKNOWN, service-worker] :: successfully unregistered the service worker')
// return the list of clients to reload in order to remove the last remnants of the service worker
return self.clients.matchAll({
type: 'window'
})
} else {
// failed unregistration
console.log('LibResilient [COMMIT_UNKNOWN, service-worker] :: failed to unregister the service worker')
// return an empty array, as it's unclear if the service worker was unregistered
return []
}
})
// reload all clients (if any)
.then(wclients => {
console.log(`LibResilient [COMMIT_UNKNOWN, service-worker] :: reloading ${wclients.length} clients`)
wclients.forEach((wclient) => {
console.log('LibResilient [COMMIT_UNKNOWN, service-worker] :: +-- client:', wclient)
wclient.navigate(wclient.url);
});
})
});
} else {
console.warn("unable to load LibResilient: ServiceWorker API not available in the browser")
}