Solvedangular cli Existing App does not get Service Worker capabilities

Versions

Angular CLI: 1.6.0
Node: 9.2.0
OS: win32 x64
Angular: 5.1.0
... animations, common, compiler, compiler-cli, core, forms
... http, language-service, platform-browser
... platform-browser-dynamic, platform-server, router
... service-worker

@angular/cli: 1.6.0
@angular-devkit/build-optimizer: 0.0.35
@angular-devkit/core: 0.0.22
@angular-devkit/schematics: 0.0.41
@ngtools/json-schema: 1.1.0
@ngtools/webpack: 1.9.0
@schematics/angular: 0.1.10
@schematics/schematics: 0.0.10
typescript: 2.6.2
webpack: 3.10.0

Repro steps

Have an existing app with no PWA capability and apply steps to upgrade it as described in docs.

Observed behavior

Despite the fact it builds with no error and dist folder has files like ngsw.json & ngsw-worker.js as expected, they are not loaded on network request when browsed. (Tested with incognito mode as well)
No service-worker effect at all in app.

Desired behavior

Service Worker added to built app when steps in official docs are applied.

Mention any other details that might be useful

On the same machine, a new app generated with Angular-CLI 1.6.0 with --service-worker flag. That app loads service worker as expected.

47 Answers

✔️Accepted Answer

I also had this issue, the culprit seams to be angularFire2. I worked around it by registering the service worker in main.ts.

platformBrowserDynamic().bootstrapModule(AppModule).then(() => {
  if ('serviceWorker' in navigator && environment.production) {
    navigator.serviceWorker.register('/ngsw-worker.js');
  }
}).catch(err => console.log(err));

Other Answers:

Service worker won't run because of ng app is not stable (ApplicationRef.isStable (https://angular.io/api/core/ApplicationRef#members), application is not becoming stable if there is a code which runs intervals (setInteral or Observable.timer and etc. which come from setInterval or setTimeout (related with NgZone.hasPendingMicrotasks)).

As example of such behaviour:

  1. Generate app ng new my-project --service-worker;
  2. First ensure what service-worker works as expected;
  3. Then add to app.component.ts constructor setInterval(t => { console.log('Ping')}, 500);
  4. Try run app again - you will see what service-worker will stops to work

Workaround for such behaviour wrap - wrap all timer-code to this.applicationRef.isStable.subscribe(isStable => { if (isStable) { <code goes here> } })

Full code

import 'rxjs/add/observable/interval';
import { Component, ApplicationRef, OnInit } from '@angular/core';
import { Observable } from 'rxjs/Observable';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  title = 'app';

  constructor(private applicationRef: ApplicationRef) {
  }

  ngOnInit() {

    this.applicationRef.isStable.subscribe((s) => { // #1
      if (s) { // #2
        setInterval(t => { console.log('Ping')}, 500);
      } // #3
    }); // #4
    // If you uncomment 1-4 - service-worker will not run

    this.applicationRef.isStable.subscribe(t => {
      console.log('App stable: ' + t);
    });
  }
}

This has definitely not been resolved yet. HNY!

I encountered also this issue on my existing app. So I tried to generate a new app like so

ng new my-project --service-worker

and after a ng build --prod it did work as expected, the service worker is registered and visible in the dev tools.

Then I tried to generate a new app like so

ng new my-project

I then followed the steps described in the guide and it did also work as expected.
So I decided to dig deeper in my own app.
After removing some code, I was able to get a service worker running and it appeared that it was due to a conflict with Pusher from the pusher-js package.

@Injectable()
export class SearchService {
  // having this assignment in a service class injected in a component in use at the startup of the app
  // makes the service worker not running (and not visible in the service worker list of the dev tools)
  pusher = new Pusher('key', { cluster: 'eu' })
  // after removing this line and doing an `ng build --prod` the service worker was running as expected.
  ...
}

I have no ideas what could be the root cause of this interaction between this line of code and the service worker as no errors are thrown in the console neither at compile time nor at runtime, but maybe this experience could help solving this issue.

The last thing I did is moving the assignment in a method that is never called at the startup of the app so I could have both a service worker registered and an instance of Pusher running.

I had the same problem. In my case it was caused by the default route in the app.module.ts

path: '', redirectTo: '/main/0', pathMatch: 'full'

With these settings the ngsw-worker.js didn't load.

More Issues: