feat(service-worker): expose `SwRegistrationOptions` token to allow runtime config (#21842)

Previously, the ServiceWorker registration options should be defined as
an object literal (in order for them to be compatible with Ahead-of-Time
compilation), thus making it impossible to base the ServiceWorker
behavior on runtime conditions.
This commit allows specifying the registration options using a regular
provider, which means that it can take advantage of the `useFactory`
option to determine the config at runtime, while still remaining
compatible with AoT compilation.

PR Close #21842
This commit is contained in:
deebloo 2019-04-25 16:51:07 +03:00 committed by Andrew Kushnir
parent d7887ab4ab
commit 39c0152b76
4 changed files with 54 additions and 7 deletions

View File

@ -15,6 +15,6 @@
*/ */
export {UpdateActivatedEvent, UpdateAvailableEvent} from './low_level'; export {UpdateActivatedEvent, UpdateAvailableEvent} from './low_level';
export {ServiceWorkerModule} from './module'; export {ServiceWorkerModule, SwRegistrationOptions} from './module';
export {SwPush} from './push'; export {SwPush} from './push';
export {SwUpdate} from './update'; export {SwUpdate} from './update';

View File

@ -14,6 +14,12 @@ import {NgswCommChannel} from './low_level';
import {SwPush} from './push'; import {SwPush} from './push';
import {SwUpdate} from './update'; import {SwUpdate} from './update';
/**
* Token that can be used to provide options for `ServiceWorkerModule` outside of
* `ServiceWorkerModule.register()`.
*
* @publicApi
*/
export abstract class SwRegistrationOptions { export abstract class SwRegistrationOptions {
scope?: string; scope?: string;
enabled?: boolean; enabled?: boolean;
@ -69,7 +75,7 @@ export class ServiceWorkerModule {
* If `enabled` is set to `false` in the given options, the module will behave as if service * If `enabled` is set to `false` in the given options, the module will behave as if service
* workers are not supported by the browser, and the service worker will not be registered. * workers are not supported by the browser, and the service worker will not be registered.
*/ */
static register(script: string, opts: {scope?: string; enabled?: boolean;} = {}): static register(script: string, opts: SwRegistrationOptions = {}):
ModuleWithProviders<ServiceWorkerModule> { ModuleWithProviders<ServiceWorkerModule> {
return { return {
ngModule: ServiceWorkerModule, ngModule: ServiceWorkerModule,

View File

@ -9,7 +9,7 @@
import {PLATFORM_ID} from '@angular/core'; import {PLATFORM_ID} from '@angular/core';
import {TestBed} from '@angular/core/testing'; import {TestBed} from '@angular/core/testing';
import {NgswCommChannel} from '@angular/service-worker/src/low_level'; import {NgswCommChannel} from '@angular/service-worker/src/low_level';
import {SwRegistrationOptions, ngswCommChannelFactory} from '@angular/service-worker/src/module'; import {ServiceWorkerModule, SwRegistrationOptions, ngswCommChannelFactory} from '@angular/service-worker/src/module';
import {SwPush} from '@angular/service-worker/src/push'; import {SwPush} from '@angular/service-worker/src/push';
import {SwUpdate} from '@angular/service-worker/src/update'; import {SwUpdate} from '@angular/service-worker/src/update';
import {MockPushManager, MockPushSubscription, MockServiceWorkerContainer, MockServiceWorkerRegistration, patchDecodeBase64} from '@angular/service-worker/testing/mock'; import {MockPushManager, MockPushSubscription, MockServiceWorkerContainer, MockServiceWorkerRegistration, patchDecodeBase64} from '@angular/service-worker/testing/mock';
@ -47,6 +47,45 @@ import {async_fit, async_it} from './async';
}); });
}); });
describe('ServiceWorkerModule config', () => {
it('SwUpdate isEnabled is false when configuring via static method', () => {
TestBed.configureTestingModule(
{imports: [ServiceWorkerModule.register('', {enabled: false})]});
expect(TestBed.get(SwUpdate).isEnabled).toEqual(false);
});
it('SwUpdate isEnabled is true when configuring via static method', () => {
TestBed.configureTestingModule({
imports: [ServiceWorkerModule.register('', {enabled: true})],
providers: [{provide: NgswCommChannel, useValue: comm}]
});
expect(TestBed.get(SwUpdate).isEnabled).toEqual(true);
});
it('SwUpdate isEnabled is false when configuring directly via token', () => {
TestBed.configureTestingModule({
imports: [ServiceWorkerModule.register('')],
providers: [{provide: SwRegistrationOptions, useFactory: () => ({enabled: false})}]
});
expect(TestBed.get(SwUpdate).isEnabled).toEqual(false);
});
it('SwUpdate isEnabled is true when configuring directly via token', () => {
TestBed.configureTestingModule({
imports: [ServiceWorkerModule.register('')],
providers: [
{provide: NgswCommChannel, useValue: comm},
{provide: SwRegistrationOptions, useFactory: () => ({enabled: true})}
]
});
expect(TestBed.get(SwUpdate).isEnabled).toEqual(true);
});
});
describe('ngswCommChannelFactory', () => { describe('ngswCommChannelFactory', () => {
it('gives disabled NgswCommChannel for platform-server', () => { it('gives disabled NgswCommChannel for platform-server', () => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({

View File

@ -1,8 +1,5 @@
export declare class ServiceWorkerModule { export declare class ServiceWorkerModule {
static register(script: string, opts?: { static register(script: string, opts?: SwRegistrationOptions): ModuleWithProviders<ServiceWorkerModule>;
scope?: string;
enabled?: boolean;
}): ModuleWithProviders<ServiceWorkerModule>;
} }
export declare class SwPush { export declare class SwPush {
@ -22,6 +19,11 @@ export declare class SwPush {
unsubscribe(): Promise<void>; unsubscribe(): Promise<void>;
} }
export declare abstract class SwRegistrationOptions {
enabled?: boolean;
scope?: string;
}
export declare class SwUpdate { export declare class SwUpdate {
readonly activated: Observable<UpdateActivatedEvent>; readonly activated: Observable<UpdateActivatedEvent>;
readonly available: Observable<UpdateAvailableEvent>; readonly available: Observable<UpdateAvailableEvent>;