-
Notifications
You must be signed in to change notification settings - Fork 316
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
Consider relying on eTags (or other headers) for service worker dependencies to check for updates #839
Comments
I think @ehsan and I had a proposal for this at some point. |
If the request is made with Else we just add |
More than checking if the main sw file changed, I'm referring to its dependencies imported via |
Yep, understand that, you'd be sending an etag (or last-modified) that represented the SW and its dependencies. Maybe that's too hacky? |
I think that undermines the purpose of the ETag about digesting the content being served. It would do the trick but I think is better to come up with something more pluggable in the actual ecosystem not requiring to hack with semantics. ;) |
Yeah, I think you're right. |
I think we should have a JS API for this, |
F2F: agreement on Lots of problems using etags for this, eg if CDN stop serving etags for some reasons. Rough idea around |
|
Was anyone able to dig up the previous proposal from @ehsan and I? I can't find it. |
+1 for this There should be a way to update the imported scripts even when the main code of the service worker is unchanged. This is also a big issue for BaaS whose scripts are imported in the customers' service workers: I have more extensively described our situation in this blog post. |
@jakearchibald Can you remind me why we don't just check importScripts() for byte changes as well? I seem to recall it was since importScripts could be called async way back when, but now we've made that throw. Since we only allow sync importScripts maybe we can just include it in the byte check. |
See issue #639 for the importScripts discussion, which roughly concluded with "let's revisit this later". |
It could mean a lot of network requests just for an update check. I was worried about that. But also it means a change to a third party script would result in a whole new SW install, which sounds a bit… invasive. I like importScripts('//example.com/whatever.js');
// then later…
self.registration.getCache().then(cache => {
cache.add('//example.com/whatever.js');
}); My big worry here is security. We'd only want the SW to be able to access this, as giving access from pages would turn a minor XSS into a huge problem. |
Sure, but this is a trade off sites can make for themselves. Do I want the convenience of structuring my code in separate files? Or do I want to minimize the number of SW script 304s my server has to send? I could see smaller shops opting for developer convenience while huge sites compacting into a single file to minimize server load.
What I'm hearing is that this is what developers expect to happen and they are surprised when it doesn't.
I like this too, but I think its a different use case. From what I can tell developers want to compose their service worker scripts from decoupled sources and have things just update to the latest. Every step we add to get the updates to trigger creates friction and requires more tight coupling between modules. At the very least it seems we could do this as an opt-in to |
If I show a "please refresh for latest version" message when there's an update waiting, I'm not sure I'd want that just because Google Analytics or whoever had updated something. Then again, third party services like Analytics will live in Foreign Fetch instead. |
Exactly! IMHO The web is so great (and Javascript is becoming pervasive) for its simplicity. Please don't create a giant and complex monster: leave that to native apps. And please don't fall into premature optimization.
I agree. But I don't think that that choice should be left to the user. What if he denies? Then he would never get updates and the scripts will finally break. I think that if you don't want all scripts to be refreshed by default you should leave to the developer the choice. For example: |
I was thinking about this: importScripts('//3rd-party.com/whatever.js', { forceUpdate: true }); // makes update algorithm to byte-to-byte compare the dependency. This way, the developer can mark the dependencies causing updates, this trade off @wanderview was talking about is made explicit at the same time you can preserve file sanity via modularization. We could make Furtheremore, if, at some time, the developer want a dependency to be part of the checking no longer, she simply flips the flag. |
Having the option in |
But do we want to make a service worker specific I think it would be better to put this on the install or activate event personally. It can then automatically apply for all |
Sure. The thing I liked about the pondering If the API was something like |
That was the idea.
Well, what I would find extremely uncomfortable is to re-declare my imports for marking purposes only. Perhaps introducing a new import function ( Dealing with ES6 modules is complicated but what about a pragma: import "my-library";
"force update";
import "my-other-library"; I don't really like it and I don't really know if there is a standard mechanism to introduce "use strict"-like pragmas in ES6 but declarative APIs are this kind of inconvenient. |
F2F:
|
When a service worker fetches a script (either the main script or imported), it will go to the network (optionally) via the HTTP cache. It won't go to the cache API or the script cache of any other service workers. |
@jakearchibald Can that lead to a situation where the resources |
@ithinkihaveacat yep. Same is true for HTML documents. We have made the HTTP cache opt-in because of developer confusion around this (#893). Developers who opt into the HTTP cache should understand how it works. |
This changes the behavior of the service worker script resource comparison. Before this, only the main service worker script was compared to a new version. With this change, all the imported scripts stored in the imported scripts map as well as the main script are inspected against the corresponding network resources (based on the urls.) Note: - Service worker's script resource map has been renamed and moved to service worker's script resource's imported scritps map. - registration's last update check time's always updated whenever the response is fetched from the network (regardless it's a main script or an imported script.) Fixes #839.
Yea, I agree they are orthogonal issues. |
An interesting point has been raised internally - is it possible we could damage sites relying on caching by making this change. I'll reach out to our biggest users and see how they feel. Worst comes to worst, we could make no-cache opt-in. |
@jakearchibald When you talk to these sites, can you also mention there is a work around if they are serving unique hashed resources? They can set |
@wanderview Sites that are able to generate unique hashed resources wouldn't really need this feature though, right? I thought the point was to make it possible for service workers to do e.g. If the default for all network activity related to service worker update checks becomes |
I guess I thought people typically versioned 3rd party dependencies. Allowing external dependencies to float at-will in production seems kind of crazy to me. |
I suppose it depends on the use case. Something like
Obviously whatever's in |
This changes the behavior of the service worker script resource comparison. Before this, only the main service worker script was compared to a new version. With this change, all the imported scripts stored in the imported scripts map as well as the main script are inspected against the corresponding network resources (based on the urls.) Note: - Service worker's script resource map has been renamed and moved to service worker's script resource's imported scritps map. - registration's last update check time's always updated whenever the response is fetched from the network (regardless it's a main script or an imported script.) Fixes #839.
Is this already implemented in Chrome or Firefox? |
Updating based on https://bugzilla.mozilla.org/show_bug.cgi?id=1290951 Related to this, defaulting updates to |
@KenjiBaheux & I should email SW users to make sure big users of SW are aware of this. |
The F2F resolution was to check importScripts in the byte-for-byte comparison; however issue #893 changed so that useCache would specify caching the importScripts by default. |
NB. Currently, updating the data resource files will not make the service worker re-cache them. The service worker file itself will need to be updated. However, browser are working on this. See: w3c/ServiceWorker#839
While working on this issue with @mattto, I found out we need to discuss about when to fetch and compare the imported classic scripts for Update. (See #1283 (comment).) Now we have two options:
(2) allows us to return early even before starting a worker. @jakearchibald seemed to be concerned about double-download (https://github.com/w3c/ServiceWorker/pull/1023/files#r92201798) here, but we can avoid But if the imported scripts in (2) have errors, we can't avoid running the main script and the cached scripts before catching those errors anyway. Thoughts? /cc @jakearchibald @wanderview @aliams @cdumez EDIT: I tried it with (1) in #1283. |
I responded in #1283 (comment), but to reiterate here, I'm much more concerned about needlessly starting a service worker in the common case than in the error case. I think we should avoid starting a service worker until the byte-to-byte update check (including importScripts) shows that an update is possible. Otherwise almost every navigation will start a new service worker to do an update check which will usually just be wasted. |
That's a fair point. I agree to (2). We can do this without doing a double-download. |
For the sake of modularization and isolation. Could it be possible to improve the update algorithm to rely on the eTag / content-size / other headers sent by the server to decide when a service worker changed? Now we need to include a mark of change in the sw and this forces a lot of developments to postprocess service worker files.
The text was updated successfully, but these errors were encountered: