7

I'm developing an app with angular5, using service workers via the ng-cli, but I realized that after the first time the app shell loads, it doesn't refresh. How can I push new file versions to my app after build it with ng build?. I could directly rewrite the sw.js manually, but as it is generated via the cli, I don't like to affect anything I don't know what is for.

I'm looking for this answer all day, but as service workers are new for the 1.6 version of the ng-cli, I have not found any.

I even found a thread similar thread for angular 4 and a unofficial service workers implementation before ng-cli 1.6, but I don't trust in that approach since it is not official, so I would like to know if you guys could help me find a way to control the way it installs the shell and looks for new versions.

Thank you

Juan Sánchez
  • 1,014
  • 2
  • 15
  • 29

2 Answers2

8

Here's what worked for me. This helps the browser detect there is a new version of the app.

App.component.ts:

    import { Component } from '@angular/core';
    import { SwUpdate } from '@angular/service-worker';

    @Component({
      selector: 'app-root',
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.css']
    })
    export class AppComponent {    
      
      constructor(public updates:SwUpdate) {
        updates.available.subscribe(event => {
          console.log('current version is', event.current);
          console.log('available version is', event.available);
        });
        updates.activated.subscribe(event => {
          console.log('old version was', event.previous);
          console.log('new version is', event.current);
        });
    
        updates.available.subscribe(event => {
            updates.activateUpdate().then(() => this.updateApp());
        });
       }
      
       updateApp(){
        document.location.reload();
        console.log("The app is updating right now");
    
       }
}

And

ngsw.json:

{
  "index": "/index.html",
  "assetGroups": [
    {
      "name": "Your app",
      "installMode": "prefetch",
      "updateMode": "lazy",
      "resources": {
        "files": [
          "/favicon.ico",
          "/index.html",
          "/*.css",
          "/*.js"
        ]
      }
    },
    {
      "name": "assets",
      "installMode": "prefetch",
      "updateMode": "lazy",
      "resources": {
        "files": [
          "/assets/**"
        ],
        "urls":[
          "https://urlsyouwanttocachefrom.com/**",
        ]
      }
    }
  ]
}

This way, every time the app is updated, the browser will autoreload.

kozenka
  • 589
  • 4
  • 6
Juan Sánchez
  • 1,014
  • 2
  • 15
  • 29
  • 1
    Not sure how it worked for you. But it did not work for me. Actually I'm expecting my application to get auto-reload when new build deployed. Am I missing something? – Pankaj Parkar Jun 05 '20 at 01:12
  • 1
    Is there a good way of testing how this would work? I'm kind of trusting your code to work, but I'm not sure how I could see for myself whether it works. Also what about outdated versions? Will they auto update as well or only versions after this? – Ruben Szekér Apr 07 '21 at 09:24
2

Based on the answer from judasane, I've managed to use the built-in SwUpdate class to manually check for updates each time the app is loaded (only showing a loading indicator at this point), and reload it when an update can be applied, hence making sure that when someone opens the app, it's always the latest version.

export class AppComponent implements OnInit {
  updateChecked = false;
  updateAvailable = false;
  
  // In your template, use this value to show a loading indicator while we are
  // waiting for updates. (You can also use it to hide the rest of the UI if
  // you want to prevent the old version from being used.)
  get waitingForUpdates() {
    return !this.updateChecked || this.updateAvailable;
  }

  constructor(private updates: SwUpdate) {}

  async ngOnInit() {
    this.updates.available.subscribe(() => {
      // Keep the loading indicator active while we reload the page
      this.updateAvailable = true;
      window.location.reload();
    });
    if (this.updates.isEnabled) {
      // This promise will return when the update check is completed,
      // and if an update is available, it will also wait for the update
      // to be downloaded (at which point it calls our callback above and
      // we just need to reload the page to apply it).
      await this.updates.checkForUpdate();
    } else {
      console.log('Service worker updates are disabled.');
    }
    // The update check is done (or service workers are disabled), now
    // we can take the loading indicator down (unless we need to apply an
    // update, but in that case, we have already set this.updateAvailable
    // to true by this point, which keeps the loading indicator active).
    this.updateChecked = true;
  }
}
Dániel Kis-Nagy
  • 2,255
  • 2
  • 18
  • 19