[w3c/ServiceWorker] Provide a way to skipWaiting when the last tab refreshes (#993)

When a service worker updates, it doesn't take control of the page right way; it goes into a "waiting" state, waiting to be activated.

Surprisingly, the updated service worker doesn't even take control of the tab after refreshing the page. Google explains:

https://developers.google.com/web/fundamentals/instant-and-offline/service-worker/lifecycle

>Even if you only have one tab open to the demo, refreshing the page isn't enough to let the new version take over. This is due to how browser navigations work. When you navigate, the current page doesn't go away until the response headers have been received, and even then the current page may stay if the response has a Content-Disposition header. Because of this overlap, the current service worker is always controlling a client during a refresh.

>To get the update, close or navigate away from all tabs using the current service worker. Then, when you navigate to the demo again, you should see the horse [updated content].

>This pattern is similar to how Chrome updates. Updates to Chrome download in the background, but don't apply until Chrome restarts. In the mean time, you can continue to use the current version without disruption. However, this is a pain during development, but DevTools has ways to make it easier, which I'll cover later in this article.

This behavior makes sense in the case of multiple tabs. My app is a bundle that needs to be updated atomically; we can't mix and match part of the old bundle and part of the new bundle. (In a native app, atomicity is automatic and guaranteed.)

But in the case of a single tab, which I'll call the "last open tab" of the app, this behavior is not what I want. I want refreshing the last open tab to update my service worker.

(It's hard to imagine that anybody actually wants the old service worker to continue running when the last open tab is refreshed. Google's "navigation overlap" argument sounds to me like a good excuse for an unfortunate bug.)

I'm developing an "app" (a game). My app is normally only used in a single tab. In production, I want my users to be able to use the latest code just by refreshing the page, but that won't work: the old service worker will remain in control across refreshes.

I don't want to have to tell users, "to receive updates, be sure to close or navigate away from my app." I want to tell them, "just refresh."

When I raised this on StackOverflow, @jakearchibald advised me to add an in-app update notification; clicking on it would post a message to the service worker, which would `skipWaiting`, and then `window.location.reload()` once the new service worker became active.

This seems like a hack, so we discussed it on Twitter. https://twitter.com/dfabu/status/789242276358651904

> Is there any way to skipWaiting on refresh? Writing my own in app refresh button seems like a hack, doesn't it?

> no, but I think such a thing would be useful (and not just on refresh, but any navigation)

> I guess this would be a "navigate" event in the service worker, which would allow you to halt navigation until skipWaiting.

> could you file a ticket on https://github.com/w3c/ServiceWorker?

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/w3c/ServiceWorker/issues/993

Received on Thursday, 20 October 2016 23:32:09 UTC