6

I want to create a website that can work even when it's server is offline — I found that that's what ServiceWorkers are for.

When I reload the page with service worker and no connectivity, it works just fine. However, shift+reload (e.g. bypassing cache) disarms service worker and I get "could not connect to server" error.

My question is — can I somehow prevent shift+reload (shift+f5, ctrl+f5 etc) from ruining service worker, or, at least, make it recover afterwards without restoring connectivity?

toriningen
  • 7,196
  • 3
  • 46
  • 68
  • I'd really like to see how this is answered but.. don't you think that deleting the cache actually defeats the purpose of caching requests with a service worker? – Mauricio Poppe Jun 01 '16 at 05:17

3 Answers3

4

I was able to keep using the service worker even after Ctrl+F5 via the following approach:

In the window script:

navigator.serviceWorker.register(<...>).then (registration => {
    if (navigator.serviceWorker.controller === null) {
        // we get here after a ctrl+f5 OR if there was no previous service worker.
        navigator.serviceWorker.ready.then(() => {
            registration.active.postMessage("claimMe");
        });
    }
    <...>
});

In the service script:

self.onmessage = (event) => {
    if (event.data === "claimMe") {
        self.clients.claim();
    }
};

In short, we ask the service worker to claim all clients again, which works even for clients that used Ctrl+F5.

If you want to respect the Ctrl+F5 in the service worker code, you could either:

  1. Clear the cache before claiming. Note that this will also affect any other existing clients, which may be unwanted.
  2. Do something more complicated like sending the id of the client that requested a Ctrl+F5 and treat fetch requests specially for such clients.
secondperson
  • 148
  • 1
  • 4
2

QUICK Answer

How to make ServiceWorker survive cache reset/Shift+F5?

Theorically (*), you can do it with js plugins which detect the key hit of Ctrl or Shift... then prevent the "force refresh" to happen

...but there is a story behind this Ctrl/Shift reload.

(*) disclaimer: I've not tried this yet


LONG story... (kind of)

This is actually a spec of Service Worker. And only present in recent change of Chrome. For the earlier version of Chrome , Service Worker has no any issue surviving a "force refresh".

Along with the spec from W3C

navigator.serviceWorker.controller returns null if the request is a force refresh (shift+refresh).

Also, there are many people (**) has suggested that a "force refresh" should always clear out all kind of caches. Which is matched with the purpose of its existent and its spec.

...Furthermore, we even got it on the wikipedia...

Wikipedia: Bypassing your cache means forcing your web browser to re-download a web page from scratch

(**) us, web developers in the early stage of service worker.

In my opinion I think it is OK to let a force refresh doing its job. Since pretty much all of us always expecting the browser to not use any cache when we doing this.

Linh Pham
  • 3,005
  • 23
  • 34
  • 1
    It starts to make difference when service workers are used to circumvent governmental censorship, or kind of — so "offline" mode is the usual or the only mode of operation, and content is delivered via other servers, or WebRTC. This way it might be beneficial to let the page survive accidental force refresh, but maybe ask user if they feel okay with it. – toriningen Jun 01 '16 at 15:13
  • @toriningen, Yeap, agreed with your comment, totally! – Linh Pham Jun 01 '16 at 20:21
  • @LinhPham Could you please share your vision on the documentation section that you've mentioned (https://w3c.github.io/ServiceWorker/#navigator-service-worker-controller)? Am I correct that navigator.serviceWorker.controller will return null in any case after the hard refresh? The problem is that it seems like it is impossible to register the service worker after hard refresh - the navigator.serviceWorker.register() promise successfully resolves, but navigator.serviceWorker.controller is still null – Aleksandr Jul 27 '18 at 13:22
0

I was able to solve this by detecting the ctrl+shift+r and reloading:

const wb = new Workbox(swUrl)
const wbReg = await wb.register({ immediate: true })

// workaround for ctrl + shift + r disabling service workers
// https://web.dev/service-worker-lifecycle/#shift-reload
if (wbReg && navigator.serviceWorker.controller === null) {
  console.error('detected ctrl+shift+r: reloading page')
  location.reload()
  throw new Error('page loaded with cache disabled: ctrl+shift+r')
}
Christian Stewart
  • 15,217
  • 20
  • 82
  • 139