user9973068
user9973068

Reputation:

Angular Service Worker SwUpdate.available not triggered

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

Answers (7)

Ahmadreza Shamimi
Ahmadreza Shamimi

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

Alex Cooper
Alex Cooper

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

Michael Doye
Michael Doye

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();
  }

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));

Upvotes: 61

Mudasser Iqbal
Mudasser Iqbal

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

Eli
Eli

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

Chellappan வ
Chellappan வ

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

ivan92
ivan92

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

Related Questions