Angular Service Worker SwUpdate.available not triggered
Solution 1
You will probably need to tell the service worker to check the server for updates, I usually use a service for this:
export class UpdateService {
constructor(public updates: SwUpdate) {
if (updates.isEnabled) {
interval(6 * 60 * 60).subscribe(() => updates.checkForUpdate()
.then(() => console.log('checking for updates')));
}
}
public checkForUpdates(): void {
this.updates.available.subscribe(event => this.promptUser());
}
private promptUser(): void {
console.log('updating to new version');
this.updates.activateUpdate().then(() => document.location.reload());
}
In your app-component.ts
:
constructor(private sw: UpdateService) {
// check the service worker for updates
this.sw.checkForUpdates();
}
For whatever reason, Angular sometimes does not register the service worker properly. So you can modify `main.ts` :
Replace:
platformBrowserDynamic().bootstrapModule(AppModule);
With:
platformBrowserDynamic().bootstrapModule(AppModule).then(() => {
if ('serviceWorker' in navigator && environment.production) {
navigator.serviceWorker.register('ngsw-worker.js');
}
}).catch(err => console.log(err));
Solution 2
I found the following info in the angular docs: https://angular.io/guide/service-worker-devops#debugging-the-angular-service-worker
Summary: There's a useful endpoint on angular sites that shows the service worker state:
http://site-url/ngsw/state
Append /ngsw/state
to your sites address. If there is something wrong with the service it should show there.
Solution 3
After every other solution on the stack didn't work, I've started debugging angular's ngsw-worker.js script. I've traced the updating logic and ended up in the "PrefetchAssetGroup" method. I've inserted logging every time method got called and then I realized that it is constantly trying to cache my favicon.ico. I've checked the location of the favicon.ico in my ngsw.json and realized that favicon is not located there. Once I've placed the icon on that location everything started working fine.
![Admin](/assets/logo_square_200-5d0d61d6853298bd2a4fe063103715b4daf2819fc21225efa21dfb93e61952ea.png)
Admin
Updated on January 12, 2021Comments
-
Admin over 3 years
I'm having a hard time integrating angulars service worker into my application. I followed the guide and it works so far. I can create a shortcut on my homescreen and launch into my app. The problem is that my app somehow doesn't update. If I change the name of a button, build the app and put it onto my server the app still shows the old version until I hit F5 (restarting the app doesn't help either).
I tried to put the following code into my ngOnInot of my app but it didn't help
ngOnInit() { if (this._SwUpdate.isEnabled) { setInterval( () => { this._SwUpdate.checkForUpdate().then(() => console.log('checking for updates')); }, this.updateInterval); this._SwUpdate.available.subscribe(() => { console.log('update found'); this._SwUpdate.activateUpdate().then(() => { console.log('updated'); window.location.reload(); }); }); }
}
The app is running on my apache2 linux machine. Is my apache caching something or why doesn't my app realize that there is a new version?
Thanks in advance for your help :)
Edit:
My ngsw-config.json
{ "index": "/index.html", "assetGroups": [{ "name": "roomPlan", "installMode": "prefetch", "resources": { "files": [ "/index.html", "/*.css", "/*.js" ] } }, { "name": "assets", "installMode": "lazy", "updateMode": "prefetch", "resources": { "files": [ "/assets/**" ] } }] }
Edit 2:
It works if I run the app local using "http-server" but when I copy the files over to my apache it doesn't detect the update. In the networking tab I can see that the interval works, the app gets a new "ngsw.json" from the server every 3 seconds. If I update my app I can see that there are new hash values inside of the response for "ngsw.json". After that the browser loads the new "index.html" and "main.***.js" from my server but the app doesn't apply the new version. According to my code it should say "update found" but nothing happens.
-
Pankaj Parkar about 4 yearsAngular docs are the best resource for this, pleaser refer this page
-
-
Admin about 6 yearsI did as you said (kept an empty tab open and restarted the http-server after making changes) but the service worker didn't update to the new version, I had to completely close the browser and start it again to get latest version. Is there maybe something wrong with my ngsw-config.json?
-
Admin about 6 yearsIt seems like the promise returned from checkForUpdate() is never fullfilled, the interval works but the 'checking for updates' never appears in my console.
-
Michael Doye about 6 yearsAre you 100% sure the service worker has been properly registered?
-
Michael Doye about 6 years@MadMurl0c check the updated answer, I modified the
promptUser
method and added something to change inmain.ts
and here is an example in a demo project -
Admin about 6 yearsStill doesn't work, the SwUpdate.available.subscribe never gets triggered but I don't know why. I put a console.log in it but I can never see it. If I build my app and place it on my server the service worker doesn't react to it at all
-
Chellappan வ about 6 yearssorry can you add this._swUpdate.checkForUpdate() inside your if condtion
-
Admin about 6 yearsThe service worker seems to work according to dev tools and after resetting my chrome data I get the "checking for updates" in my console, the app doesn't update though, it seems like he's checking for updates but never realizing that there is an updated version.. Could my apache somehow cache the version number so that my service worker doesn't know that there is a new one?
-
Admin about 6 yearsI'm using an interval which checks for updates every 10sec but it doesn't react to the new version (I updated my code sample)
-
Admin about 6 yearsThanks, now the service worker gets started correctly and not only on every ~3rd try, but it still doesn't update although it atleast checks for updates now
-
Michael Doye about 6 yearsdid you see the update to
promptUser
which now activates the update usingthis.updates.activateUpdate().then(() => document.location.reload()));
-
Admin about 6 yearsI'm not sure if I'm allowed to share the whole code because it's an internal project. Which files could I provide to help?
-
Admin about 6 yearsYes I saw that and I integrated it into my code (updated the example in my first post) but this part never gets called, I put a console.log in there just to make sure but it doesn't detect the update
-
Chellappan வ about 6 yearsdid you added this.swUpdate.checkForUpdate() inside your ngOnInit lifecycle hook?
-
Admin about 6 yearsHow can I find out if my Apache is the problem? Unfortunately I can't put my project onto a public server
-
Michael Doye about 6 yearsNot 100% sure, but this answer might be useful - stackoverflow.com/a/34161385/3055401
-
Admin about 6 yearsI did but it didn't change anything. If it runs the checkForUpdate() method I can see that it request 3 files in the network tab "ngsw.json?ngws-cache-burst=...., config.php, config.php?ngsw-cache-burst=..." I don't know why my config.php is in there but that's all what happens
-
Admin about 6 yearsJust that I understand SwUpdate right... I go into my app, write "hello world" in any component, ng build --prod my app, copy it to my apache2 and the service worker should refresh it... right?
-
Michael Doye about 6 yearsThat's right yes, check the debug log at yourdomain.com/ngsw/state and see if there is anything in the Task queue
-
Admin about 6 yearsGreat news.. It now works with http-server! So my apache must be the problem, but what could it be?
-
Admin about 6 yearsThe app gets the new ngsw.json file and theres a new hash for main.js in it but the service worker doesn't load the new version of main.js... On localhost it works fine
-
Admin about 6 yearsAfter completely disabling cache he loads the new main.js but it doens't trigger the update subscription
-
Admin almost 6 yearsI just completely reseted my test system and set up a new apache server.. After applying your fix in the main.ts everything works now, thanks for helping me out
-
Vytautas Pranskunas almost 6 yearsService worker is not registered sometimes only because you have setInterval and app is never stable from the beginning because it is triggering ngZOne change detection. To avoid this run all intervals outside angular.
-
ishandutta2007 about 5 yearsERROR in ..: error TS2304: Cannot find name 'interval'.
-
ishandutta2007 about 5 yearswhere is navigator defined.
-
Kim about 5 yearswindow.navigator @ishandutta2007
-
Kim about 5 years@VytautasPranskunas can you elaborate on "run all intervals outside angular"?
-
ishandutta2007 about 5 yearsI couldn't make it work. created a new question with the issues i am geting from this code. @Yeswhen you can take a peek too stackoverflow.com/questions/55797611/…
-
Angad about 5 yearsI am having the same issue. Can you tell me what did you do to fix this? Do I need to disable caching on server? It works for me on http-server but when I host it on azure box the available event is never triggered.
-
Kim about 5 yearsYes, the server should not cache ngsw-worker.js. Did you register the service worker in main.ts like in the answer above? You can try register it by yourself in the console by writing navigator.serviceWorker.register('ngsw-worker.js'), maybe the path is different in your azure box @Angad
-
Bhaumik Thakkar about 5 years@MichaelDoye can you please tell me the proper testing scenario(basically how can I verify that it's working properly or not?) for service worker in local mode.
-
Michael Doye about 5 years@BhaumikThakkar please see the docs here: angular.io/guide/…
-
Abner almost 5 years@MichaelDoye Is this solution still valid and recommended for Angular V8? I notice after an update my PWA in IOS did not reload the page, meaning it probably didn't trigger the activateUpdate()
-
Tahseen Quraishi over 4 yearsIt worked for me. I did same as @MichaelDoye has suggested.
-
Jimmy Kane about 4 yearsI dont understand this solution to be honest. Why the setInterval? Could you be a bit more explanatory in your answer? For me it works as it should at the time of writing but are having other problems so I do like the answer but don't understand the flow.
-
Michael Doye about 4 years@JimmyKane the
interval
is there because we need to poll the server to check for updates, this is described in the documentation (although their implementation has changed a bit) -
iwantcheeseburger almost 4 yearsHi @MichaelDoye, I've tried your solution and it works fine in my case, but is there any alternative where if it check for an update then found one, that updates.checkForUpdate method will be stopped? because it is calling every 20 secs and I dont want to overload the server call. Thanks.
-
Aaron Turkel almost 3 years