This is boiling down the discussions from https://github.com/slightlyoff/ServiceWorker/issues/445 & meetings into a few options.
//docs.google.com/spreadsheets/d/docid and //docs.google.com/a/mozilla.com/spreadsheets/d/docidnavigator.serviceWorker.register(scriptURL, {
// name is the ID of the registration, rather than scope, as it is now
// name is optional, defaults to empty string which is a valid ID
name: "my-app-name"
// Scope is optional, can be null, a string, or an array of strings
// Default is null
// null means the SW will not receive any fetch events
scope: "/spreadsheets/"
}).then(function(reg) {
reg.name === "my-app-name";
// Getting the scope
reg.scopeList.get().then(arrayOfScopes => {});
// Setting the scope
reg.scopeList.set(arrayOrString).then(() => {});
// Adding
reg.scopeList.add("/a/mozilla.com/spreadsheets/").then(() => {});
// Removing
reg.scopeList.remove("/a/mozilla.com/spreadsheets/").then(() => {});
// scope-change operations reject if another SW controls that scope
});
// Getting the above registration
navigator.serviceWorker.getRegistration("my-app-name").then(reg => {});
// Getting the default no-name registration
navigator.serviceWorker.getRegistration().then(reg => {});
// Get the registration that would be used for a navigation to url
navigator.serviceWorker.getRegistrationControlling(url).then(reg => {});
reg.name never changes & is the "primary key" of the registrationAs proposal 1, except scope defaults to /. Scope can still be set to null or an empty array to opt out of fetch events.
reg.name never changes & is the "primary key" of the registrationnavigator.serviceWorker.register(scriptURL, {
// Scope is required & is the ID of the SW
// Can be a string, or an array of strings
// Default is "/"
// An empty array means the SW will not receive any fetch events
scope: "/spreadsheets/"
}).then(function(reg) {
reg.scopeList; // same as proposal 1
});
// Get the registration that would be used for a navigation to url.
// If url is ommited, gets the registration for the current document/worker url
navigator.serviceWorker.getRegistration(url).then(reg => {});
// The worker without scopes can only be found via:
navigator.serviceWorker.getRegistrations().then(regs => {});
// Unless getRegistration does something special with an empty string
Compatible with the current API, aside from potentially losing reg.scope (no longer appropriate for sync access, I think)
Proposal 1: opt-in fetch events, new name property for identifying registrations
All proposals allow changing scope, multiple scopes, and no scopes.
Meeting summary:
null scopes, it's something we can add later if we see people using scopes of /this/path/totally/doesnt/exist.setScope() to the ActivateEvent object to accomplish this (still needs to be async as it rejects if another registration uses this scope)reg.scope as a sync getter, it's no worse than reg.installing etc['/a/', '/b/'], and a page calls .register(scriptURL, {scope: '/a/'}) does it reject or resolve with the registration with scope ['/a/', '/b/']?//docs.google.com/spreadsheets/d/docid and //docs.google.com/a/mozilla.com/spreadsheets/d/docid are actually seperate apps with seperate binaries etc, as is Google's settings page, so we're still lacking in examples of one app with disjointed paths//github.com/settings/ & //github.com/watching/ may be an example, as may Evernote - @sicking can you look into Evernote?@slightlyoff are you agreed on having a way to move scopes during activation? Am I right in thinking you want further evidence on the need for multiple scopes?
@jakearchibald changing scope during activation would allow also to set the scope to a parent path or it will still be forbidden?
@jakearchibald :
Yes, agreed to API for moving scopes during activation.
Also correct that we don't yet have a compelling example that demands multiple scopes and that examples along those lines would help convince me of the need.
Optional: allow ServiceWorkers to be created that don't care about fetch events
It seems to me this goal can already be mostly met by the UA optimizing around the onfetch handler not being set. If there are no fetch event handlers then the UA can skip network interception completely. This state would need to be persisted when the SW shutdown.
If the SW has terminated, and an event needs to fire within the SW, the SW should only spin up if an event listener of that type was added last time the SW started.
Does that work? @annevk, how do you feel about that?
This would break cases where listener adding wasn't consistent, such as adding depending on Math.random() or Date.now(), but I'm cool with that.
This would break cases where listener adding wasn't consistent, such as adding depending on Math.random() or Date.now(), but I'm cool with that.
Yea, I think this falls in the same bucket as async importScripts(), saving state on the global, etc. Its not going to work consistently and should be discouraged in SW scripts.
I think an explicit switch would be way better than anything that requires observing whether or not there is an event listener added.
I feel that this issue and others like issue #1026 or issue #1272 and the long-thought-after static routes are similar in that they are about refining if/how a Service Worker gets involved.
I know that there is strong interest on those issues, including from Google and Facebook. I'm wondering if we can identify a path forward. So, here is my modest contribution to the discussion.
Currently, we can only define that a Service Worker gets involved for a navigation to anything below its scope (prefix match) on a given origin.
I've heard about the following use cases:
Use case 1
This use case feels different than the other use cases because it only refines one thing, the (primary) scope. The primary scope also happens to be essential to the registration step. So, it seems natural to have this on the register call, via a new option (e.g. strict match vs. prefix). I believe that this was one of the various proposals on the relevant issue.
Use cases 2, 3 and 4
On the other hand, use cases 2, 3 and 4 can consist of multiple refinements which are not essential to the registration step and are most likely not critical for the developer (e.g. having a secondary scope fail because a different team has already registered a primary-scoped SW will likely be considered as WAI by the developer).
It seems:
For comparison, if we were to do these refinements as part of the register call, then it seems harder for a developer to reason about why the call failed, or separate the critical from the optional, etc.
Now, I'm not saying that the methods have to be identical - they accept different things after all - but having a similar feel should be possible and welcomed. e.g. re-use the strict match vs. prefix option, parallelism of method names (addScope, addRoute), etc.
Also, while addressing use case Nb 4 would also cover use case Nb 2, I think we should be able to proceed with an MVP for Nb 2 while keeping in mind the generic use cases in Nb 4.
Handling scope conflicts
Tentative strawman:
Does this sound reasonable?
Presumably you can have multiple secondary scopes and only one primary scope per service worker?
Yes. One primary, multiple secondaries.
Most helpful comment
I feel that this issue and others like issue #1026 or issue #1272 and the long-thought-after static routes are similar in that they are about refining if/how a Service Worker gets involved.
I know that there is strong interest on those issues, including from Google and Facebook. I'm wondering if we can identify a path forward. So, here is my modest contribution to the discussion.
Currently, we can only define that a Service Worker gets involved for a navigation to anything below its scope (prefix match) on a given origin.
I've heard about the following use cases:
Use case 1
This use case feels different than the other use cases because it only refines one thing, the (primary) scope. The primary scope also happens to be essential to the registration step. So, it seems natural to have this on the register call, via a new option (e.g. strict match vs. prefix). I believe that this was one of the various proposals on the relevant issue.
Use cases 2, 3 and 4
On the other hand, use cases 2, 3 and 4 can consist of multiple refinements which are not essential to the registration step and are most likely not critical for the developer (e.g. having a secondary scope fail because a different team has already registered a primary-scoped SW will likely be considered as WAI by the developer).
It seems:
For comparison, if we were to do these refinements as part of the register call, then it seems harder for a developer to reason about why the call failed, or separate the critical from the optional, etc.
Now, I'm not saying that the methods have to be identical - they accept different things after all - but having a similar feel should be possible and welcomed. e.g. re-use the strict match vs. prefix option, parallelism of method names (addScope, addRoute), etc.
Also, while addressing use case Nb 4 would also cover use case Nb 2, I think we should be able to proceed with an MVP for Nb 2 while keeping in mind the generic use cases in Nb 4.
Handling scope conflicts
Tentative strawman:
Does this sound reasonable?