Open jeffposnick opened 3 years ago
A workaround for now:
let readType = false;
navigator.serviceWorker
.register('about:blank', {
get type() {
readType = true;
},
})
.catch(() => {});
If readType
is false, it doesn't understand type
.
While that does detect type
support in general, it isn't sufficient to detect type: 'module'
support. Both Chrome 90 and Safari 14.0.3 support type
but don't work with type: 'module'
.
In the case of Chrome 90, there's an exception throw immediately (DOMException: type 'module' in RegistrationOptions is not implemented yet.See https://crbug.com/824647 for details.
), so it does avoid downloading and parsing the script.
In the case of Safari 14.0.3, the ES module version of the script downloads and then fails to parse, with a TypeError: SyntaxError: Unexpected token '*'. import call expects exactly one argument.
, so checking for type
doesn't avoid the problem. I'm assuming this is because Safari 14.0.3 shipped with partially implemented ES module support, as the Technology Previews post-122 work as expected.
sighhhhh that Safari issue is frustrating.
https://static-misc-2.glitch.me/detect-sw-module-support/ - here's a test that works today, although it requires a network request.
Epic 😄 It's good to have that to refer folks to if they want to use ES modules today and also want to avoid a potential double-download. Long-term, is a more official mechanism for detecting support reasonable to add to the service worker specification?
Actually, since ES modules in dedicated workers are already supported in Chrome and Safari, how do developers using them deal with what I'm assuming is a similar issue? ~Perhaps a way of feature-detecting support needs to be done on the WorkerGlobalScope
level, to address that use case as well?~
(EDIT: Although I guess code in the window
scope can't interrogate the WorkerGlobalScope
, so that probably wouldn't help.)
Perhaps a way of feature-detecting support needs to be done on the
WorkerGlobalScope
level, to address that use case as well?
It'd be nice to be able to detect it without starting up a worker. Although, at least with a worker you can avoid the network request. But yeah, it'd be good to have the same solution in both places.
Going to see if I can make the test better, so it might be broken for a bit…
Maybe not a great general solution, but would there be any benefit in changing the Service-Worker: script
header to say Service-Worker: module
when type is module
and its supported? That way the server could dynamically choose to return either a classic or module script.
Going to see if I can make the test better, so it might be broken for a bit…
I couldn't make it better. I thought Safari might support the type
option but ignore the value. But no, it validates it (I guess they have the IDL), but doesn't do the right thing with the value.
@wanderview
Maybe not a great general solution, but would there be any benefit in changing the
Service-Worker: script
header to sayService-Worker: module
when type ismodule
and its supported?
That seems nice!
If https://github.com/w3c/ServiceWorker/issues/1585 is resolved, and dynamic import()
comes to service workers, it would introduce one more capability that would be important to know prior to service worker registration.
You could theoretically create four different versions of a service worker script—importScripts()
vs. static module imports, and dynamic import()
s vs. no dynamic support—to cover all the possible variations, and registering them one at a time until you find the one that doesn't throw isn't a good model. (Though I doubt it's likely that a browser will support dynamic import() but not static module imports...)
Exposing some combination of ['classic', 'dynamic', 'static']
as a new importSupport
property on the ServiceWorkerContainer
, reflecting the set of capabilities of the current browser, would address this expanded use case. Browsers that don't have an importSupport
property on ServiceWorkerContainer
could be assumed to only support classic importScripts()
.
Maybe not a great general solution, but would there be any benefit in changing the Service-Worker: script header to say Service-Worker: module when type is module and its supported?
That seems nice!
Should we pursue this?
I think a client-side solution would be a more general solution. Might not be worth spending time on the header thing yet?
I've recently been experimenting with ES modules for service workers, now supported in pre-stable versions of Chrome and Safari.
I've found that without a way to feature detect support, writing code that's backwards compatible can be awkward, and in some browsers, less performant.
Roughly, this is the registration snippet that I was trying out:
Pre-stable versions of Chrome and Safari will successfully run the first registration, and the current stable versions of Chrome will raise an exception immediately because it "knows" that
type: 'module'
isn't supported.However, the current stable versions of Firefox and Safari will download and attempt to execute the ES module flavor of service worker, and only raise an exception when there's a syntax error due to the usage of ES module imports. The fallback logic in the
catch
can successfully register a classic version of the service worker that usesimportScripts()
, but not until after spending the bandwidth and time needed to download and parse something that we should know in advance won't work.Am I missing something already implemented in all browsers that would make it possible to feature-detect
type: 'module'
support ahead of time? If not, consider this a feature request to add in a property, presumably exposed on theServiceWorkerContainer
, that could answer the "are ES module service workers supported?" question in advance of attempting the registration. Either a boolean that wastrue
when ES modules are supported, or alternatively, a list of supportedtype
values, set in this case to['classic', 'module']
, if we think that there might be additionaltype
s that will be added in the future.