fix(service-worker): prevent SW registration strategies from affecting app stabilization (#35870)

Previously, some of the built-in ServiceWorker registration strategies,
namely `registerWithDelay:<timeout>` and `registerWhenStable:<timeout>`,
would register potentially long-running timeout, thus preventing the app
from stabilizing before the timeouts expired. This was especially
problematic for the `registerWhenStable:<timeout>` strategy, which waits
for the app to stabilize, because the strategy itself would prevent the
app from stabilizing and thus the ServiceWorker would always be
registered after the timeout.

This commit fixes this by subscribing to the registration strategy
observable outside the Angular zone, thus not affecting the app's
stabilization.

PR Close #35870
This commit is contained in:
Sonu Kapoor 2020-03-24 22:54:54 +02:00 committed by Alex Rickabaugh
parent 29e8a64cf0
commit 2d7c95fb70
1 changed files with 9 additions and 4 deletions

View File

@ -7,7 +7,7 @@
*/
import {isPlatformBrowser} from '@angular/common';
import {APP_INITIALIZER, ApplicationRef, InjectionToken, Injector, ModuleWithProviders, NgModule, PLATFORM_ID} from '@angular/core';
import {APP_INITIALIZER, ApplicationRef, InjectionToken, Injector, ModuleWithProviders, NgModule, NgZone, PLATFORM_ID} from '@angular/core';
import {Observable, merge, of } from 'rxjs';
import {delay, filter, take} from 'rxjs/operators';
@ -122,10 +122,15 @@ export function ngswAppInitializer(
}
// Don't return anything to avoid blocking the application until the SW is registered.
// Also, run outside the Angular zone to avoid preventing the app from stabilizing (especially
// given that some registration strategies wait for the app to stabilize).
// Catch and log the error if SW registration fails to avoid uncaught rejection warning.
readyToRegister$.pipe(take(1)).subscribe(
() => navigator.serviceWorker.register(script, {scope: options.scope})
.catch(err => console.error('Service worker registration failed with:', err)));
const ngZone = injector.get(NgZone);
ngZone.runOutsideAngular(
() => readyToRegister$.pipe(take(1)).subscribe(
() =>
navigator.serviceWorker.register(script, {scope: options.scope})
.catch(err => console.error('Service worker registration failed with:', err))));
};
return initializer;
}