Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add registeringClientId to the ServiceWorker object #1379

Open
philipwalton opened this issue Jan 2, 2019 · 2 comments
Open

Add registeringClientId to the ServiceWorker object #1379

philipwalton opened this issue Jan 2, 2019 · 2 comments

Comments

@philipwalton
Copy link
Member

philipwalton commented Jan 2, 2019

On the Workbox team, we're currently building a library that will run in the window context and aid in SW registration, updates, and lifecycle management (design doc).

One thing I discovered while working on an early prototype is there are use cases we want to support that are currently not possible (or they're super hacky) to achieve given the current spec.

Here's an example of two cases that are very difficult to reliably distinguish between (AFAIK):

  • Tab A registers a SW, and that registration triggers an updatefound event.
  • Tab A registers a SW and no update is triggered. But before tab A closes, tab B registers a SW for the same script and an updatefound event is triggered.

The code running in tab A cannot easily tell that the updated SW wasn't triggerred by its call to navigator.serviceWorker.register().

This isn't necessarily a big problem if the SW code doesn't call skipWaiting(), or if it just displays a reload banner any time an update is found, but realistically there are cases where webapps want to be more aggressive about updates, or perform in-place updates, and in those cases it's really important to know whether the given update is the one your app was expecting or a future update your code isn't prepared to handle.

I think a reasonable addition to the SW spec would be a property like registeringClientId, which would match the client of the window that executed the navigator.serviceWorker.register() code.

Then, in an updatefound callback, a page could compare its clientId (my understanding is we want to expose the Clients API on the window at some point) to the registeringClientId property on event.target.installing and determine whether the update came from its version of the code.


Another possible solution (arguably cleaner but probably also less doable), is a change to the way register() works. At the moment, there's no easy way to tell if a register() call didn't result in an update. If the result of calling register() (or some new method) came with any sort of signal for when an update was not found, then it would make the above issue a lot easier to solve, as you'd know you wouldn't need to add any updatefound event listeners in that case.

@jakearchibald
Copy link
Contributor

Calls to register don't trigger updates unless the registration is new or is being modified in some way. Or is that what you mean?

The browser can technically update the service worker whenever it wants. It doesn't need to be linked to a client.

Can you talk a bit more about why you want some tabs to react to the update, and others to not-react?

@philipwalton
Copy link
Member Author

philipwalton commented Sep 16, 2019

Looking back on this issue several months later, I'm not sure registeringClientId is the right solution to this problem—though I do think the use case is worth solving.

Let me clarify the use case:

  • Tab A is loaded with v1 of the app code and service worker.
  • Tab B is loaded an hour later, and in the time since tab A was loaded, an updated version (v2) of the app and service worker has been released.
  • When tab B is loaded, both A and B will get the updatefound event, but only tab B is running window code released with the same version as the updated service worker (v2).

For apps the do a lot of SW to window post messaging, the scenario described above could result in a lot of errors for tab A, so tab A would likely want to show a notification to the user that they should reload, whereas tab B will likely work just fine.

So, the use case is to enable a way for a developer receiving an updatefound event to know whether or not the update found is:

  • "expected" (i.e. from a version of the service worker released at the same time as the version of the current window code)
  • "unexpected" (i.e. from a newer version of the service worker, released more recently than the currently-running window code)

The problem, currently, is that when window code calls either register() or update(), there's no good way to determine whether or not that call resulted in an update being found. On the flip side, when an updatefound event is received, there's no good way to determine whether or not it was the result of that page's call to register()/update(), or whether it was the result of a register()/update() call in another tab or even the browser doing its own soft update check as you mentioned.

I'm not tied to any particular solution to this problem, but if we could add a way for a page to reason about whether an updatefound event is "expected" or "unexpected", that would be really helpful in knowing how to react to the update.

Some possible solutions:

  • Expose the time Last-Modified time of the service worker file on the updatefound event. (Then developers could compare that time to performance.timeOrigin).
  • Expose the last time the browser checked for an update prior to finding this one (not sure if this has security implications or not)
  • Expose whether or not the update found was directly the result of a register()/update() call from the current document (or whether it was from another document or a soft update check).
  • Change the return value of the async .update() method to something that indicates whether or not an update was found (note: currently the return value in the WebIDL for update() is wrong, so maybe it's OK to make such a change?)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants