fix(service-worker): ensure initialised in browser only (#20782)
closes #20360 PR Close #20782
This commit is contained in:
parent
da3563ce19
commit
7cabaa0ae7
|
@ -12,7 +12,8 @@
|
||||||
"tslib": "^1.7.1"
|
"tslib": "^1.7.1"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@angular/core": "0.0.0-PLACEHOLDER"
|
"@angular/core": "0.0.0-PLACEHOLDER",
|
||||||
|
"@angular/common": "0.0.0-PLACEHOLDER"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|
|
@ -11,6 +11,7 @@ const sourcemaps = require('rollup-plugin-sourcemaps');
|
||||||
|
|
||||||
const globals = {
|
const globals = {
|
||||||
'@angular/core': 'ng.core',
|
'@angular/core': 'ng.core',
|
||||||
|
'@angular/common': 'ng.common',
|
||||||
|
|
||||||
'rxjs/BehaviorSubject': 'Rx',
|
'rxjs/BehaviorSubject': 'Rx',
|
||||||
'rxjs/ConnectableObservable': 'Rx',
|
'rxjs/ConnectableObservable': 'Rx',
|
||||||
|
|
|
@ -6,7 +6,8 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {Injectable} from '@angular/core';
|
import {isPlatformBrowser} from '@angular/common';
|
||||||
|
import {Inject, Injectable, PLATFORM_ID} from '@angular/core';
|
||||||
import {BehaviorSubject} from 'rxjs/BehaviorSubject';
|
import {BehaviorSubject} from 'rxjs/BehaviorSubject';
|
||||||
import {Observable} from 'rxjs/Observable';
|
import {Observable} from 'rxjs/Observable';
|
||||||
import {ConnectableObservable} from 'rxjs/observable/ConnectableObservable';
|
import {ConnectableObservable} from 'rxjs/observable/ConnectableObservable';
|
||||||
|
@ -86,8 +87,11 @@ export class NgswCommChannel {
|
||||||
*/
|
*/
|
||||||
readonly events: Observable<IncomingEvent>;
|
readonly events: Observable<IncomingEvent>;
|
||||||
|
|
||||||
constructor(private serviceWorker: ServiceWorkerContainer|undefined) {
|
constructor(
|
||||||
if (!serviceWorker) {
|
private serviceWorker: ServiceWorkerContainer|undefined,
|
||||||
|
@Inject(PLATFORM_ID) platformId: string) {
|
||||||
|
if (!serviceWorker || !isPlatformBrowser(platformId)) {
|
||||||
|
this.serviceWorker = undefined;
|
||||||
this.worker = this.events = this.registration = errorObservable(ERR_SW_NOT_SUPPORTED);
|
this.worker = this.events = this.registration = errorObservable(ERR_SW_NOT_SUPPORTED);
|
||||||
} else {
|
} else {
|
||||||
const controllerChangeEvents =
|
const controllerChangeEvents =
|
||||||
|
|
|
@ -6,7 +6,8 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {APP_INITIALIZER, ApplicationRef, Inject, InjectionToken, Injector, ModuleWithProviders, NgModule} from '@angular/core';
|
import {isPlatformBrowser} from '@angular/common';
|
||||||
|
import {APP_INITIALIZER, ApplicationRef, Inject, InjectionToken, Injector, ModuleWithProviders, NgModule, PLATFORM_ID} from '@angular/core';
|
||||||
import {Observable} from 'rxjs/Observable';
|
import {Observable} from 'rxjs/Observable';
|
||||||
import {filter as op_filter} from 'rxjs/operator/filter';
|
import {filter as op_filter} from 'rxjs/operator/filter';
|
||||||
import {take as op_take} from 'rxjs/operator/take';
|
import {take as op_take} from 'rxjs/operator/take';
|
||||||
|
@ -24,10 +25,12 @@ export abstract class RegistrationOptions {
|
||||||
export const SCRIPT = new InjectionToken<string>('NGSW_REGISTER_SCRIPT');
|
export const SCRIPT = new InjectionToken<string>('NGSW_REGISTER_SCRIPT');
|
||||||
|
|
||||||
export function ngswAppInitializer(
|
export function ngswAppInitializer(
|
||||||
injector: Injector, script: string, options: RegistrationOptions): Function {
|
injector: Injector, script: string, options: RegistrationOptions,
|
||||||
|
platformId: string): Function {
|
||||||
const initializer = () => {
|
const initializer = () => {
|
||||||
const app = injector.get<ApplicationRef>(ApplicationRef);
|
const app = injector.get<ApplicationRef>(ApplicationRef);
|
||||||
if (!('serviceWorker' in navigator) || options.enabled === false) {
|
if (!(isPlatformBrowser(platformId) && ('serviceWorker' in navigator) &&
|
||||||
|
options.enabled !== false)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const onStable =
|
const onStable =
|
||||||
|
@ -51,8 +54,10 @@ export function ngswAppInitializer(
|
||||||
return initializer;
|
return initializer;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ngswCommChannelFactory(opts: RegistrationOptions): NgswCommChannel {
|
export function ngswCommChannelFactory(
|
||||||
return new NgswCommChannel(opts.enabled !== false ? navigator.serviceWorker : undefined);
|
opts: RegistrationOptions, platformId: string): NgswCommChannel {
|
||||||
|
return new NgswCommChannel(
|
||||||
|
opts.enabled !== false ? navigator.serviceWorker : undefined, platformId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -75,11 +80,15 @@ export class ServiceWorkerModule {
|
||||||
providers: [
|
providers: [
|
||||||
{provide: SCRIPT, useValue: script},
|
{provide: SCRIPT, useValue: script},
|
||||||
{provide: RegistrationOptions, useValue: opts},
|
{provide: RegistrationOptions, useValue: opts},
|
||||||
{provide: NgswCommChannel, useFactory: ngswCommChannelFactory, deps: [RegistrationOptions]},
|
{
|
||||||
|
provide: NgswCommChannel,
|
||||||
|
useFactory: ngswCommChannelFactory,
|
||||||
|
deps: [RegistrationOptions, PLATFORM_ID]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
provide: APP_INITIALIZER,
|
provide: APP_INITIALIZER,
|
||||||
useFactory: ngswAppInitializer,
|
useFactory: ngswAppInitializer,
|
||||||
deps: [Injector, SCRIPT, RegistrationOptions],
|
deps: [Injector, SCRIPT, RegistrationOptions, PLATFORM_ID],
|
||||||
multi: true,
|
multi: true,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
|
@ -20,12 +20,12 @@ export function main() {
|
||||||
let comm: NgswCommChannel;
|
let comm: NgswCommChannel;
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
mock = new MockServiceWorkerContainer();
|
mock = new MockServiceWorkerContainer();
|
||||||
comm = new NgswCommChannel(mock as any);
|
comm = new NgswCommChannel(mock as any, 'browser');
|
||||||
});
|
});
|
||||||
describe('NgswCommsChannel', () => {
|
describe('NgswCommsChannel', () => {
|
||||||
it('can access the registration when it comes before subscription', (done: DoneFn) => {
|
it('can access the registration when it comes before subscription', (done: DoneFn) => {
|
||||||
const mock = new MockServiceWorkerContainer();
|
const mock = new MockServiceWorkerContainer();
|
||||||
const comm = new NgswCommChannel(mock as any);
|
const comm = new NgswCommChannel(mock as any, 'browser');
|
||||||
const regPromise = mock.getRegistration() as any as MockServiceWorkerRegistration;
|
const regPromise = mock.getRegistration() as any as MockServiceWorkerRegistration;
|
||||||
|
|
||||||
mock.setupSw();
|
mock.setupSw();
|
||||||
|
@ -34,13 +34,18 @@ export function main() {
|
||||||
});
|
});
|
||||||
it('can access the registration when it comes after subscription', (done: DoneFn) => {
|
it('can access the registration when it comes after subscription', (done: DoneFn) => {
|
||||||
const mock = new MockServiceWorkerContainer();
|
const mock = new MockServiceWorkerContainer();
|
||||||
const comm = new NgswCommChannel(mock as any);
|
const comm = new NgswCommChannel(mock as any, 'browser');
|
||||||
const regPromise = mock.getRegistration() as any as MockServiceWorkerRegistration;
|
const regPromise = mock.getRegistration() as any as MockServiceWorkerRegistration;
|
||||||
|
|
||||||
comm.registration.subscribe(reg => { done(); });
|
comm.registration.subscribe(reg => { done(); });
|
||||||
|
|
||||||
mock.setupSw();
|
mock.setupSw();
|
||||||
});
|
});
|
||||||
|
it('is disabled for platform-server', () => {
|
||||||
|
const mock = new MockServiceWorkerContainer();
|
||||||
|
const comm = new NgswCommChannel(mock as any, 'server');
|
||||||
|
expect(comm.isEnabled).toEqual(false);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
describe('SwPush', () => {
|
describe('SwPush', () => {
|
||||||
let push: SwPush;
|
let push: SwPush;
|
||||||
|
@ -72,7 +77,7 @@ export function main() {
|
||||||
expect(() => TestBed.get(SwPush)).not.toThrow();
|
expect(() => TestBed.get(SwPush)).not.toThrow();
|
||||||
});
|
});
|
||||||
describe('with no SW', () => {
|
describe('with no SW', () => {
|
||||||
beforeEach(() => { comm = new NgswCommChannel(undefined); });
|
beforeEach(() => { comm = new NgswCommChannel(undefined, 'browser'); });
|
||||||
it('can be instantiated', () => { push = new SwPush(comm); });
|
it('can be instantiated', () => { push = new SwPush(comm); });
|
||||||
it('does not crash on subscription to observables', () => {
|
it('does not crash on subscription to observables', () => {
|
||||||
push = new SwPush(comm);
|
push = new SwPush(comm);
|
||||||
|
@ -166,7 +171,7 @@ export function main() {
|
||||||
expect(() => TestBed.get(SwUpdate)).not.toThrow();
|
expect(() => TestBed.get(SwUpdate)).not.toThrow();
|
||||||
});
|
});
|
||||||
describe('with no SW', () => {
|
describe('with no SW', () => {
|
||||||
beforeEach(() => { comm = new NgswCommChannel(undefined); });
|
beforeEach(() => { comm = new NgswCommChannel(undefined, 'browser'); });
|
||||||
it('can be instantiated', () => { update = new SwUpdate(comm); });
|
it('can be instantiated', () => { update = new SwUpdate(comm); });
|
||||||
it('does not crash on subscription to observables', () => {
|
it('does not crash on subscription to observables', () => {
|
||||||
update = new SwUpdate(comm);
|
update = new SwUpdate(comm);
|
||||||
|
|
|
@ -80,7 +80,7 @@ export function main() {
|
||||||
async_beforeEach(async() => {
|
async_beforeEach(async() => {
|
||||||
// Fire up the client.
|
// Fire up the client.
|
||||||
mock = new MockServiceWorkerContainer();
|
mock = new MockServiceWorkerContainer();
|
||||||
comm = new NgswCommChannel(mock as any);
|
comm = new NgswCommChannel(mock as any, 'browser');
|
||||||
scope = new SwTestHarnessBuilder().withServerState(server).build();
|
scope = new SwTestHarnessBuilder().withServerState(server).build();
|
||||||
driver = new Driver(scope, scope, new CacheDatabase(scope, scope));
|
driver = new Driver(scope, scope, new CacheDatabase(scope, scope));
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,8 @@
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
"rootDir": ".",
|
"rootDir": ".",
|
||||||
"paths": {
|
"paths": {
|
||||||
"@angular/core": ["../../dist/packages/core"]
|
"@angular/core": ["../../dist/packages/core"],
|
||||||
|
"@angular/common": ["../../dist/packages/common"]
|
||||||
},
|
},
|
||||||
"outDir": "../../dist/packages/service-worker"
|
"outDir": "../../dist/packages/service-worker"
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in New Issue