JWrightII
JWrightII

Reputation: 1084

SwUpdate Not Working On First Load Before First Service Worker Registered

I'm trying to use a service worker to deliver prompt updates to users actively using the site. Followed the simple steps laid out in: https://angular.io/guide/service-worker-getting-started but I'm having issues with the initial load of the site.

My approach was to have a basic global service using providedIn:'root' that would take in angular's SwUpdate service to watch for any updates and prompt the user to activate/refresh.

But using the suggested registration strategy of 'registerWhenStable:30000' - the very first time the user hits the site, there is no service worker until it's stable or 30s have passed. You can watch the dev tools "Application -> Service Worker" tab and see that nothing is there for about 30s and then it spins up. But even once it's been registered, that SW never seems to be attached to angular's SwUpdate service. None of the versionUpdates events fire, the checkForUpdate() method never returns the boolean, nothing. The checkForUpdate() method is especially strange because the promise just dies...it doesn't resolve or reject, I have no idea what it's doing. I can deploy a dozen new versions of the site and they'll never be noticed.

However, if after that first load, I refresh the page now so that now SwUpdate and my own service are initialized while the sw has already been registered, everything works great! I can see all the events, the and checkForUpdate() works as you'd expect and notifies the user of new deployments. But I kind of want to include first time users in the pool of people that are receiving updates 😅

I've tried doing goofy things like delaying wiring all the subscriptions until after that first 30s window has passed but I can't seem to get SwUpdate to ever return anything on that first load where there is no immediate service worker. Refreshing the page once after the very first load of the page is the only thing I've found to get SwUpdate service tracking. Anyone have ideas what I'm screwing up here?

My changes are pretty by the book, but just in case it'll help here's what I have:

// app.config.ts
export const appConfig: ApplicationConfig = {
  providers: [
    provideServiceWorker('ngsw-worker.js', {
      enabled: !isDevMode(),
      registrationStrategy: 'registerWhenStable:30000',
    }),
    ...
    NewAppVersionTrackerService,
  ],
};
//new-app-version-tracker.service.ts
@Injectable({ providedIn: 'root' })
export class NewAppVersionTrackerService {
  private checkIntervalSeconds = 300;
  
  constructor(
    private dialogService: DialogService,
    private swUpdate: SwUpdate,
    private zone: NgZone,
  ) {}

  public init() {
    this.watchForUpdates()
  }

  private watchForUpdates(): void {
    if (!this.swUpdate.isEnabled) {
      return;
    }

    this.zone.runOutsideAngular(() => {
      interval(this.checkIntervalSeconds * 1000).subscribe(() => {
        console.log('Checking for SW Update');
        this.swUpdate
          .checkForUpdate()
          .then((versionFound) => { console.log('Check for update result:', versionFound); })
      });
    });

    this.swUpdate.versionUpdates.subscribe((versionEvent) => {
      switch (versionEvent.type) {
        case 'VERSION_DETECTED':
          console.info(`New application version found, beginning download: ${versionEvent.version.hash}`);
          break;
        case 'VERSION_READY':
          console.info(`New app version ready: ${versionEvent.latestVersion.hash}`);
          this.dialogService.open(DynamicNewApplicationVersionReadyDialogComponent);
          break;
        case 'VERSION_INSTALLATION_FAILED':
          console.warn(`New application version found but failed to install (hash: ${versionEvent.version.hash}): ${versionEvent.error}`);
          break;
      }
    });
  }
}

Upvotes: 0

Views: 181

Answers (0)

Related Questions