Reputation:
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.
Upvotes: 56
Views: 37364
Reputation: 73
I wrote this code for trigger new version Maybe helpful for you,
ngOnInit(): void {
this.updates.versionUpdates
.pipe(
filter((evt): evt is VersionReadyEvent => evt.type === 'VERSION_READY'),
switchMap(() =>
this.snackBar
.open('New version available', 'Update now')
.afterDismissed()
),
filter((result) => result.dismissedByAction),
map(() => this.updates.activateUpdate().then(() => location.reload()))
)
.subscribe();
}
Upvotes: 0
Reputation: 597
I've been using the solution in the accepted answer from Michael Doye for some time, but it stopped working when I upgraded to Angular 14.
The solution below is derived from comment by Vytautas Pranskunas
Run interval outside Angular using NgZone
constructor(public swUpdate: SwUpdate, private ngZone: NgZone) {
if (swUpdate.isEnabled) {
this.ngZone.runOutsideAngular(() =>
interval(1000 * 10).subscribe(val => {
swUpdate
.checkForUpdate()
.then(_ => console.log('SW Checking for updates'));
})
);
}
(Checking every 10 seconds for test purposes - increase the interval for production)
Upvotes: 0
Reputation: 8171
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();
}
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));
Upvotes: 61
Reputation: 27
To check if newer a version of Angular is available, you can call below method from any component, or just copy the IsNewerVersionAvailable
method in app.component
.
export class DataService {
constructor(private http: HttpClient, private swUpdate: SwUpdate) { }
private available: boolean = false;
IsNewerVersionAvailable() {
if (this.swUpdate.isEnabled) {
this.swUpdate.available.subscribe(() => {
this.available = true;
});
console.log(this.available);
}
return this.available;
}
}
Upvotes: -4
Reputation: 1836
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.
Upvotes: 13
Reputation: 27471
Making changes to your application you need to this method activateUpdate(
import { SwUpdate } from '@angular/service-worker';
export class AppComponent implements OnInit {
constructor(private swUpdate: SwUpdate) { }
ngOninit() {
this.swUpdate.available.subscribe(event => {
console.log('A newer version is now available. Refresh the page now to update the cache');
});
this.swUpdate.checkForUpdate()
}
}
Check this Link:https://angular.io/guide/service-worker-getting-started
Upvotes: 0
Reputation: 81
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.
Upvotes: 8