feat(service-worker): allow configuring when the SW is registered (#21842)

Fixes #20970

PR Close #21842
This commit is contained in:
JiaLi.Passion 2018-01-29 01:38:16 +09:00 committed by Andrew Kushnir
parent aa53d6cc6d
commit 4cfba58072
4 changed files with 58 additions and 16 deletions

View File

@ -218,3 +218,15 @@ If the field is omitted, it defaults to:
'!/**/*__*/**', // Exclude URLs containing `__` in any other segment. '!/**/*__*/**', // Exclude URLs containing `__` in any other segment.
] ]
``` ```
## `register options`
<code-example path="service-worker-getting-started/src/app/app.module.ts" linenums="false" header="src/app/app.module.ts" region="sw-module"> </code-example>
You can pass some options to the `register()` method.
- enabled: optional parameter, by default is true, if enabled is false, the module will behave like the browser not support service worker, and service worker will not be registered.
- scope: optional parameter, to specify the subset of your content that you want the service worker to control.
- registrationStrategy: optional parameter, specify a strategy that determines when to register the service worker, the available options are:
- registerWhenStable: this is the default behavior, the service worker will register when the application is stable (no microTasks or macroTasks remain).
- registerImmediately: register immediately without waiting the application to become stable.
- registerDelay:timeout : register after the timeout period, `timeout` is the number of milliseconds to delay registration. For example `registerDelay:5000` would register the service worker after 5 seconds. If the number of `timeout` is not given (`registerDelay`), by default, `timeout` will be `0`, but it is not equal to `registerImmediately`, it will still run a `setTimeout(register, 0)` to wait all `microTasks` to finish then perform registration of the service worker.
- A factory to get Observable : you can also specify a factory which returns an Observable, the service worker will be registered the first time that a value is emitted by the Observable.

View File

@ -1,7 +1,7 @@
# Getting started with service workers # Getting started with service workers
This document explains how to enable Angular service worker support in projects that you created with the [Angular CLI](cli). It then uses a simple example to show you a service worker in action, demonstrating loading and basic caching. This document explains how to enable Angular service worker support in projects that you created with the [Angular CLI](cli). It then uses a simple example to show you a service worker in action, demonstrating loading and basic caching.
#### Prerequisites #### Prerequisites
@ -10,26 +10,26 @@ A basic understanding of the information in [Introduction to Angular service wor
## Adding a service worker to your project ## Adding a service worker to your project
To set up the Angular service worker in your project, use the CLI command `ng add @angular/pwa`. It takes care of configuring your app to use service workers by adding the `service-worker` package along To set up the Angular service worker in your project, use the CLI command `ng add @angular/pwa`. It takes care of configuring your app to use service workers by adding the `service-worker` package along
with setting up the necessary support files. with setting up the necessary support files.
```sh ```sh
ng add @angular/pwa --project *project-name* ng add @angular/pwa --project *project-name*
``` ```
The above command completes the following actions: The above command completes the following actions:
1. Adds the `@angular/service-worker` package to your project. 1. Adds the `@angular/service-worker` package to your project.
2. Enables service worker build support in the CLI. 2. Enables service worker build support in the CLI.
3. Imports and registers the service worker in the app module. 3. Imports and registers the service worker in the app module.
4. Updates the `index.html` file: 4. Updates the `index.html` file:
* Includes a link to add the `manifest.json` file. * Includes a link to add the `manifest.json` file.
* Adds meta tags for `theme-color`. * Adds meta tags for `theme-color`.
5. Installs icon files to support the installed Progressive Web App (PWA). 5. Installs icon files to support the installed Progressive Web App (PWA).
6. Creates the service worker configuration file called [`ngsw-config.json`](/guide/service-worker-config), which specifies the caching behaviors and other settings. 6. Creates the service worker configuration file called [`ngsw-config.json`](/guide/service-worker-config), which specifies the caching behaviors and other settings.
Now, build the project: Now, build the project:
```sh ```sh
ng build --prod ng build --prod
@ -40,8 +40,8 @@ The CLI project is now set up to use the Angular service worker.
## Service worker in action: a tour ## Service worker in action: a tour
This section demonstrates a service worker in action, This section demonstrates a service worker in action,
using an example application. using an example application.
### Serving with `http-server` ### Serving with `http-server`
@ -61,7 +61,7 @@ With the server running, you can point your browser at http://localhost:8080/. Y
### Simulating a network issue ### Simulating a network issue
To simulate a network issue, disable network interaction for your application. In Chrome: To simulate a network issue, disable network interaction for your application. In Chrome:
1. Select **Tools** > **Developer Tools** (from the Chrome menu located at the top right corner). 1. Select **Tools** > **Developer Tools** (from the Chrome menu located at the top right corner).
2. Go to the **Network tab**. 2. Go to the **Network tab**.
@ -73,9 +73,9 @@ To simulate a network issue, disable network interaction for your application. I
Now the app has no access to network interaction. Now the app has no access to network interaction.
For applications that do not use the Angular service worker, refreshing now would display Chrome's Internet disconnected page that says "There is no Internet connection". For applications that do not use the Angular service worker, refreshing now would display Chrome's Internet disconnected page that says "There is no Internet connection".
With the addition of an Angular service worker, the application behavior changes. On a refresh, the page loads normally. With the addition of an Angular service worker, the application behavior changes. On a refresh, the page loads normally.
If you look at the Network tab, you can verify that the service worker is active. If you look at the Network tab, you can verify that the service worker is active.
@ -107,12 +107,12 @@ Pay attention to two key points:
### Making changes to your application ### Making changes to your application
Now that you've seen how service workers cache your application, the Now that you've seen how service workers cache your application, the
next step is understanding how updates work. next step is understanding how updates work.
1. If you're testing in an incognito window, open a second blank tab. This will keep the incognito and the cache state alive during your test. 1. If you're testing in an incognito window, open a second blank tab. This will keep the incognito and the cache state alive during your test.
2. Close the application tab, but not the window. This should also close the Developer Tools. 2. Close the application tab, but not the window. This should also close the Developer Tools.
3. Shut down `http-server`. 3. Shut down `http-server`.
@ -156,4 +156,4 @@ The service worker installed the updated version of your app *in the background*
## More on Angular service workers ## More on Angular service workers
You may also be interested in the following: You may also be interested in the following:
* [Communicating with service workers](guide/service-worker-communications). * [Communicating with service workers](guide/service-worker-communications).

View File

@ -8,6 +8,7 @@
import {isPlatformBrowser} from '@angular/common'; 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, PLATFORM_ID} from '@angular/core';
import {Observable} from 'rxjs';
import {filter, take} from 'rxjs/operators'; import {filter, take} from 'rxjs/operators';
import {NgswCommChannel} from './low_level'; import {NgswCommChannel} from './low_level';
@ -41,6 +42,8 @@ export abstract class SwRegistrationOptions {
* [ServiceWorkerContainer#register()](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerContainer/register). * [ServiceWorkerContainer#register()](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerContainer/register).
*/ */
scope?: string; scope?: string;
registrationStrategy?: (() => Observable<any>)|string;
} }
export const SCRIPT = new InjectionToken<string>('NGSW_REGISTER_SCRIPT'); export const SCRIPT = new InjectionToken<string>('NGSW_REGISTER_SCRIPT');
@ -68,7 +71,33 @@ export function ngswAppInitializer(
// Don't return the Promise, as that will block the application until the SW is registered, and // Don't return the Promise, as that will block the application until the SW is registered, and
// cause a crash if the SW registration fails. // cause a crash if the SW registration fails.
whenStable.then(() => navigator.serviceWorker.register(script, {scope: options.scope})); if (typeof options.registrationStrategy === 'function') {
const observable = options.registrationStrategy();
const subscription = observable.subscribe(() => {
navigator.serviceWorker.register(script, {scope: options.scope});
subscription.unsubscribe();
});
} else {
const registrationStrategy = typeof options.registrationStrategy === 'string' ?
options.registrationStrategy :
'registerWhenStable';
if (registrationStrategy === 'registerWhenStable') {
whenStable.then(() => navigator.serviceWorker.register(script, {scope: options.scope}));
} else if (registrationStrategy === 'registerImmediately') {
navigator.serviceWorker.register(script, {scope: options.scope});
} else if (registrationStrategy.indexOf('registerDelay') !== -1) {
const split = registrationStrategy.split(':');
const delayStr = split.length > 1 ? split[1] : undefined;
const delay = Number(delayStr);
setTimeout(
() => navigator.serviceWorker.register(script, {scope: options.scope}),
typeof delay === 'number' ? delay : 0);
} else {
// wrong strategy
throw new Error(
`Unknown service worker registration strategy: ${options.registrationStrategy}`);
}
}
}; };
return initializer; return initializer;
} }

View File

@ -21,6 +21,7 @@ export declare class SwPush {
export declare abstract class SwRegistrationOptions { export declare abstract class SwRegistrationOptions {
enabled?: boolean; enabled?: boolean;
registrationStrategy?: (() => Observable<any>) | string;
scope?: string; scope?: string;
} }