Service Worker: Hash Mismatch
See original GitHub issueI’d like to use this to start a discussion based upon a topic I talked about with @gkalpak at ng-conf 2018.
As mentioned in #21288, the service worker implementation checkes the hashes of the cached files and if they don’t match, it just serves the data from the network (which is like having no service worker).
The problem is that every proxy on the web can manipulate the files downloaded. This is especially the case for mobile providers that are minifying and inlining a lot of stuff on the fly to save bandwith. But also tools like live-server change the index.html (and so they can be used to reproduce this issue).
As one of the big use cases for PWAs are areas with low bandwith, this is somehow conflicting.
Perhaps one way to solve this is to provide an exchangeable HashCheckStrategy. In cases where I as the programmer wants to take the responsiblity for not checking the hashes in order to bypass this issue, I could write sth like this:
export class BruceWillisHashCheckStrategy implements HashCheckStrategy {
check(currentHash, expectedHash, fileName) {
return true;
}
}
Issue Analytics
- State:
- Created 5 years ago
- Reactions:20
- Comments:52 (17 by maintainers)
Top Related StackOverflow Question
One reason is to conserve bandwidth (which might be significant if you cache large, rarely-changing files, like images, etc.)
But that is not the main reason (as far as I understand).
There is the concept of an app version. An app version contains all the files that comprise the app. This info is captured in a “manifest” file (
ngsw.json), which is used by the SW to find out about a new app version.Note that the SW may serve different app versions to different app instances (e.g. different tabs). The SW guarantees that each app instance will continue to receive the files that correspond to its assigned version. This is important, because if your user has the app open in tab 1, and you deploy a new version with an updated asset (which might be incompatible with the old app version - e.g. a new JS script that expects the new
index.htmllayout and breaks if used with the old one), you don’t want the user to suddenly start getting the new incompatible asset, while still using the oldindex.html.Therefore, it is important for the SW to be able to tell if an asset file belongs to a specific version. The only reliable way discussed so far is comparing the content (which btw is also what browsers do for detecting modified ServiceWorker scripts).
For example, imagine you deploy version 2 which includes
foo.jsas an asset. The SW detects the new version and starts downloading the assets for that version. In the meantime, you deploy version 3, with a modifiedfoo.js. When SW requestsfoo.jsto cache it for version 2, it will receive the new (backwards incompatible)foo.jsfrom version 3 (because that is now deployed to the server). If it were to happily cache and serve that version with the rest of the app files for version 2, your app would be broken.Essentially, the SW needs to be able to tell whether a received file is actually the one that belongs to the current version it is updating to. Also, lazily fetched assets (with
installMode: 'lazy') complicate things even more.I am sure there are other usecases, but in general the idea is that the SW needs to be able to tell whether the files that it receives, when fetching for a specific app version, do indeed correspond to the files that where on disk when that version’s build was created.
Verifying the content is the only reliable way that has come up so far (and doing it via a hash is a cheap way to achieve this) 😃
I got the issue fixed by:
html-minifier -o dist/index.html dist/index.html --remove-comments --collapse-whitespace --minify-js --minify-cssterser dist/combined-sw.js -o dist/combined-sw.js -c --comments /^##/. (for some reason--comments falsewas not working so I added this--comments /^##/to remove all comments).ngsw-config dist ngsw-config.json@gkalpak @filipesilva what if Angular CLI could minify these files as well during the build process?