Issue
Edit Summary: I've created a minimal reproducible example
I no longer believe this is related to css or any @font-face
declaration for that matter. The problem lies with the official Angular way of swUpdate.checkForUpdate()
possibly in conjunction with appRef.isStable
subscription.
What I believe is happening now is that the swUpdate service provided by angular is messing up with thinking that there is an actual update, even though hashed values of cached content remain the same.
I figured this out by changing all of my css files in my angular.json
file to look like the following:
{
"input": "node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
"bundleName": "material-theme",
"inject": false
}
then I made a simple service to add the bundled style sheets to my header. I could add them at any point in time, even choosing to add them minutes after the application loaded (and the swUpdate event below fired multiple different times).
const appIsStable$ = this.appRef.isStable.pipe(takeWhile(isStable => isStable === true));
const everyMinute$ = interval(60*1000);
const swUpdateCheck$ = concat(appIsStable$, everyMinute$);
swUpdateCheck$.subscribe(() => {
console.log('update check');
this.swUpdate.checkForUpdate().then(() => {
console.log('new version available');
if(this.window.confirm('New version available. Click OK to download')){
this.swUpdate.activateUpdate().then(() => {
this.window.location.reload();
});
}
}, (rej) => {
debugger;
});
});
It still gives me my prompt to update the application.
There are 2 things I read about this -
- Devtools might actually be distrupting the natural cycle of how the service worker runs cache-busting.
- The way that Angular recommends you to subscribe to their observable event via
checkForUpdates()
and using anapp.isStable
event fires multiple times.
I've created a minimal reproducible example and have indeed confirmed that the main update problem lies with the checking for update methodology in Angular's official docs.
simply npm install
then run a http-server instance like so from the dist folder
http-server -p 4200 -c-1 ./sw-css-test
And you'll see what I mean!
Original Post:
The Problem - Without physically changing any file, the service worker thinks there is an update to go out and get.
The Situation: Using Angular 10 configured with SW available. Multiple libraries imported such as Angular Material, etc.
The Theory: Angular material tries to go out and get the Google font 'Roboto' (if it can't find it in the local file tree) as noted in the following snippet from my bundled style.css file. Because it is using the url() function as a fallback, it goes to look for this in the cache and finds it, UNMODIFIED as indicated from the 304 response from the service worker. However, because the style.css file changed (presumably because it found the font?) it comes back with a 200 response. This then prompts cache busting of the service worker and it thinks that there is an update to go out and get.
Once you get the update, rinse, wash, repeat, and you have an infinite update loop. This is bad for trying to prompt a user when there is an actual update of your app that they should go download. Why is this happening?
The below snipped from the bundled css.
@font-face {
font-family: Roboto;
font-style: normal;
font-weight: 400;
src: local("Roboto"),local("Roboto-Regular"),url(roboto-v20-latin-ext_latin-regular.5cb5c8f08bb4e6cb64c3.woff2) format("woff2"),url(roboto-v20-latin-ext_latin-regular.ae804dc012b1b5255474.woff) format("woff")
}
@font-face {
font-family: Roboto;
font-style: normal;
font-weight: 500;
src: local("Roboto Medium"),local("Roboto-Medium"),url(roboto-v20-latin-ext_latin-500.0b45721325446d537b54.woff2) format("woff2"),url(roboto-v20-latin-ext_latin-500.e492ac63197a57e7f4d3.woff) format("woff")
}
@font-face {
font-family: Roboto;
font-style: normal;
font-weight: 700;
src: local("Roboto Bold"),local("Roboto-Bold"),url(roboto-v20-latin-ext_latin-700.1d1ef7788f0ff084b881.woff2) format("woff2"),url(roboto-v20-latin-ext_latin-700.8aba6dc5d991e4367d7a.woff) format("woff")
}
Snippet from the Network tab
Am I thinking along the right lines here?
The Proposed Solution: Figure out a way to tell the material library to reference a static version of Roboto.
Is there any other solution that might be better?
For reference my ngsw-config.json:
{
"$schema": "../node_modules/@angular/service-worker/config/schema.json",
"index": "/index.html",
"assetGroups": [
{
"name": "app",
"installMode": "prefetch",
"resources": {
"files": [
"/favicon.ico",
"/index.html",
"/manifest.webmanifest",
"/*.css",
"/*.js"
]
}
},
{
"name": "assets",
"installMode": "lazy",
"updateMode": "prefetch",
"resources": {
"files": [
"/assets/**",
"/*.(eot|svg|cur|jpg|png|webp|gif|otf|ttf|woff|woff2|ani)"
]
}
}
]
}
Note: I have tried removing all css files and ttf, woff, and woff2 assets from the service worker. Yet it still comes back with an update.
Any help is greatly appreciated. Thank you.
Solution
Have you tried looking at the v10 specific documentation and checking to make sure it is working as you are describing above?
It looks like the promise always resolves no matter what - even if there is an update or not. Try using the available
observable in conjunction with checkForUpdate()
?
Also, try pulling your manifest file out of the ngsw-config.json
and see if that doesn't help as well. I've seen hash mismatching in that file before.
What does the output of ngsw/state
after your config.url say?
Answered By - CupofJoe
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.