Closed mkArtakMSFT closed 4 years ago
Nope, looks good
@SteveSandersonMS But it would be nice that you don't have to download all assets on pwa update if you only changed one css file for example. I think the best way to save the most of the bandwith would be to generate hashed Urls (I mean the hash inside the path of the url or in the query string) and serving the "immutable" files with a long Cache-Control: max-age. With this approach only the modified files will be downloaded on service-worker update instead of all files. Jake Archibald has a good article to that topic: https://jakearchibald.com/2016/caching-best-practices/
I tried an alternative approach with completely ignoring the browser http cache but that does not work. I thought I could get the non-modified files from the previous cache(s) in the service-worker and only download the modified ones.
async function onInstall(event) {
// ...
await caches.open(cacheName).then(cache => {
cache.add(new Request('index.html'));
let requestsToFetch = [];
Promise.all(assetsRequests.map(async (request) => {
const response = await caches.match(request);
if (response) {
return cache.put(request, response);
}
else {
requestsToFetch.push(request);
return Promise.resolve();
}
})).then(() => {
return cache.addAll(requestsToFetch);
});
});
}
// await caches.open(cacheName).then(cache => cache.addAll(assetsRequests));
But unfortunately this does not take the subresource integrity into account. So it will cache everything.
Will the current solution work when hosting the app on a CDN?
How does the blazor boot handle the case where the CDN still delivers the old content for some of the paths? If the service worker does hash validation it can only note that the files are wrong, it can't recover until all files are updated in the cache which could be 15 minutes.
If a third-party tool would generate hashes for the filenames, would it be enough to rename the files and update the paths in index.html
, blazor.webassembly.js
and blazor.boot.json
?
Upon testing I found that I can update index.html
and change filename of blazor.webassembly.js
and blazor.boot.json
. But once I try to rename files referenced in blazor.boot.json
the runtime fail with an error.
However I was successful in adding a hash to the _framework
folder and update paths in index.html
and blazor.webassembly.js
.
Will this be a stable solution?
But it would be nice that you don't have to download all assets on pwa update if you only changed one css file for example.
As long as your server returns etags for the responses, the client won't re-download anything it already has. The server will return 304 Not Modified
for those resources. No need for changing the URLs.
Will the current solution work when hosting the app on a CDN?
A CDN generally wants to host multiple versions of libraries so people can pick whatever version they need. So I'd expect a CDN to expose URLs like https://some.example.cdn/blazorwebassembly/3.2.0/dotnet.wasm
(etc).
Note that the recently-added CDN support lets you generate any URLs you want. So for example you could programmatically add the first 8 chars of the integrity hash to the URL and request things like https://some.example.cdn/blazorwebassembly/your.application-4a30bcf2.dll
.
But it would be nice that you don't have to download all assets on pwa update if you only changed one css file for example.
As long as your server returns etags for the responses, the client won't re-download anything it already has. The server will return
304 Not Modified
for those resources. No need for changing the URLs.
@SteveSandersonMS The point is, that if I use "Cache-Control" on my server with a long max-age then my server will not be asked again if it were changed within that period of time (great 👍, less requests) but it will fail to update the service-worker because it will use the cached one and says nope, this file does not have a valid subresource integrity and stops the update process of the service worker.
I hope I was able to bring over my concern.
The cost of the requests that return 304 shouldn't be significant, because we don't request the _framework
files at all once they are already cached.
We only request one of the _framework
files per app startup, i.e., the blazor.boot.json file which tells us the hashes of all the other files, and hence we know whether to use the locally-cached copies based on those hashes.
As such there's literally no reason to use cache-control with a long max-age, since we're caching them permanently (that is, until their hashes in blazor.boot.json change) anyway.
I don't think there's anything else for us to do here. We now have the content hashes in the
blazor.boot.json
file (and service worker asset manifest for PWAs), and the.js
code already takes care of requesting them withcache: no-cache
when they are not already cached locally.@javiercn Please comment if you think something else is still needed here, but I'll close now because I think this is now handled.