Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions packages/examples/service-worker/registration-options/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package(default_visibility = ["//visibility:public"])

load("//packages/bazel:index.bzl", "protractor_web_test_suite")
load("//tools:defaults.bzl", "ng_module", "ts_library")
load("@npm_bazel_typescript//:index.bzl", "ts_devserver")

ng_module(
name = "sw_registration_options_examples",
srcs = glob(
["**/*.ts"],
exclude = ["**/*_spec.ts"],
),
# TODO: FW-1004 Type checking is currently not complete.
type_check = False,
deps = [
"//packages/core",
"//packages/platform-browser",
"//packages/platform-browser-dynamic",
"//packages/service-worker",
],
)

ts_library(
name = "sw_registration_options_e2e_tests_lib",
testonly = True,
srcs = glob(["**/e2e_test/*_spec.ts"]),
tsconfig = "//packages/examples:tsconfig-e2e.json",
deps = [
"//packages/examples/test-utils",
"//packages/private/testing",
"@npm//@types/jasminewd2",
"@npm//protractor",
],
)

ts_devserver(
name = "devserver",
entry_module = "@angular/examples/service-worker/registration-options/main",
index_html = "//packages/examples:index.html",
port = 4200,
scripts = [
"//tools/rxjs:rxjs_umd_modules",
"@npm//node_modules/tslib:tslib.js",
],
static_files = [
"ngsw-worker.js",
"@npm//node_modules/zone.js:dist/zone.js",
],
deps = [":sw_registration_options_examples"],
)

protractor_web_test_suite(
name = "protractor_tests",
data = ["//packages/bazel/src/protractor/utils"],
on_prepare = "start-server.js",
server = ":devserver",
deps = [
":sw_registration_options_e2e_tests_lib",
"@npm//protractor",
"@npm//selenium-webdriver",
],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/

import {browser, by, element} from 'protractor';
import {verifyNoBrowserErrors} from '../../../test-utils';

describe('SW `SwRegistrationOptions` example', () => {
const pageUrl = '/registration-options';
const appElem = element(by.css('example-app'));

afterEach(verifyNoBrowserErrors);

it('not register the SW by default', () => {
browser.get(pageUrl);
expect(appElem.getText()).toBe('SW enabled: false');
});

it('register the SW when navigating to `?sw=true`', () => {
browser.get(`${pageUrl}?sw=true`);
expect(appElem.getText()).toBe('SW enabled: true');
});
});
12 changes: 12 additions & 0 deletions packages/examples/service-worker/registration-options/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/

import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
import {AppModuleNgFactory} from './module.ngfactory';

platformBrowserDynamic().bootstrapModuleFactory(AppModuleNgFactory);
49 changes: 49 additions & 0 deletions packages/examples/service-worker/registration-options/module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
// tslint:disable: no-duplicate-imports
import {Component} from '@angular/core';
// #docregion registration-options
import {NgModule} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';
import {ServiceWorkerModule, SwRegistrationOptions} from '@angular/service-worker';
// #enddocregion registration-options
import {SwUpdate} from '@angular/service-worker';
// tslint:enable: no-duplicate-imports

@Component({
selector: 'example-app',
template: 'SW enabled: {{ swu.isEnabled }}',
})
export class AppComponent {
constructor(readonly swu: SwUpdate) {}
}
// #docregion registration-options

@NgModule({
// #enddocregion registration-options
bootstrap: [
AppComponent,
],
declarations: [
AppComponent,
],
// #docregion registration-options
imports: [
BrowserModule,
ServiceWorkerModule.register('ngsw-worker.js'),
],
providers: [
{
provide: SwRegistrationOptions,
useFactory: () => ({enabled: location.search.includes('sw=true')}),
},
],
})
export class AppModule {
}
// #enddocregion registration-options
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/

// Mock `ngsw-worker.js` used for testing the examples.
// Immediately takes over and unregisters itself.
self.addEventListener('install', evt => evt.waitUntil(self.skipWaiting()));
self.addEventListener(
'activate',
evt => evt.waitUntil(self.clients.claim().then(() => self.registration.unregister())));
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/

const protractorUtils = require('@angular/bazel/protractor-utils');
const protractor = require('protractor');

module.exports = async function(config) {
const {port} = await protractorUtils.runServer(config.workspace, config.server, '-port', []);
const serverUrl = `http://localhost:${port}`;

protractor.browser.baseUrl = serverUrl;
};
2 changes: 1 addition & 1 deletion packages/service-worker/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@
*/

export {UpdateActivatedEvent, UpdateAvailableEvent} from './low_level';
export {ServiceWorkerModule} from './module';
export {ServiceWorkerModule, SwRegistrationOptions} from './module';
export {SwPush} from './push';
export {SwUpdate} from './update';
40 changes: 32 additions & 8 deletions packages/service-worker/src/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,39 @@ import {NgswCommChannel} from './low_level';
import {SwPush} from './push';
import {SwUpdate} from './update';

export abstract class RegistrationOptions {
scope?: string;
/**
* Token that can be used to provide options for `ServiceWorkerModule` outside of
* `ServiceWorkerModule.register()`.
*
* You can use this token to define a provider that generates the registration options at runtime,
* for example via a function call:
*
* {@example service-worker/registration-options/module.ts region="registration-options"
* header="app.module.ts" linenums="false"}
*
* @publicApi
*/
export abstract class SwRegistrationOptions {
/**
* Whether the ServiceWorker will be registered and the related services (such as `SwPush` and
* `SwUpdate`) will attempt to communicate and interact with it.
*
* Default: true
*/
enabled?: boolean;

/**
* A URL that defines the ServiceWorker's registration scope; that is, what range of URLs it can
* control. It will be used when calling
* [ServiceWorkerContainer#register()](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerContainer/register).
*/
scope?: string;
}

export const SCRIPT = new InjectionToken<string>('NGSW_REGISTER_SCRIPT');

export function ngswAppInitializer(
injector: Injector, script: string, options: RegistrationOptions,
injector: Injector, script: string, options: SwRegistrationOptions,
platformId: string): Function {
const initializer = () => {
const app = injector.get<ApplicationRef>(ApplicationRef);
Expand Down Expand Up @@ -50,7 +74,7 @@ export function ngswAppInitializer(
}

export function ngswCommChannelFactory(
opts: RegistrationOptions, platformId: string): NgswCommChannel {
opts: SwRegistrationOptions, platformId: string): NgswCommChannel {
return new NgswCommChannel(
isPlatformBrowser(platformId) && opts.enabled !== false ? navigator.serviceWorker :
undefined);
Expand All @@ -69,22 +93,22 @@ export class ServiceWorkerModule {
* 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.
*/
static register(script: string, opts: {scope?: string; enabled?: boolean;} = {}):
static register(script: string, opts: SwRegistrationOptions = {}):
ModuleWithProviders<ServiceWorkerModule> {
return {
ngModule: ServiceWorkerModule,
providers: [
{provide: SCRIPT, useValue: script},
{provide: RegistrationOptions, useValue: opts},
{provide: SwRegistrationOptions, useValue: opts},
{
provide: NgswCommChannel,
useFactory: ngswCommChannelFactory,
deps: [RegistrationOptions, PLATFORM_ID]
deps: [SwRegistrationOptions, PLATFORM_ID]
},
{
provide: APP_INITIALIZER,
useFactory: ngswAppInitializer,
deps: [Injector, SCRIPT, RegistrationOptions, PLATFORM_ID],
deps: [Injector, SCRIPT, SwRegistrationOptions, PLATFORM_ID],
multi: true,
},
],
Expand Down
18 changes: 9 additions & 9 deletions packages/service-worker/test/comm_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import {PLATFORM_ID} from '@angular/core';
import {TestBed} from '@angular/core/testing';
import {NgswCommChannel} from '@angular/service-worker/src/low_level';
import {RegistrationOptions, ngswCommChannelFactory} from '@angular/service-worker/src/module';
import {SwRegistrationOptions, ngswCommChannelFactory} from '@angular/service-worker/src/module';
import {SwPush} from '@angular/service-worker/src/push';
import {SwUpdate} from '@angular/service-worker/src/update';
import {MockPushManager, MockPushSubscription, MockServiceWorkerContainer, MockServiceWorkerRegistration, patchDecodeBase64} from '@angular/service-worker/testing/mock';
Expand Down Expand Up @@ -52,10 +52,10 @@ import {async_fit, async_it} from './async';
TestBed.configureTestingModule({
providers: [
{provide: PLATFORM_ID, useValue: 'server'},
{provide: RegistrationOptions, useValue: {enabled: true}}, {
{provide: SwRegistrationOptions, useValue: {enabled: true}}, {
provide: NgswCommChannel,
useFactory: ngswCommChannelFactory,
deps: [RegistrationOptions, PLATFORM_ID]
deps: [SwRegistrationOptions, PLATFORM_ID]
}
]
});
Expand All @@ -66,10 +66,10 @@ import {async_fit, async_it} from './async';
TestBed.configureTestingModule({
providers: [
{provide: PLATFORM_ID, useValue: 'browser'},
{provide: RegistrationOptions, useValue: {enabled: false}}, {
{provide: SwRegistrationOptions, useValue: {enabled: false}}, {
provide: NgswCommChannel,
useFactory: ngswCommChannelFactory,
deps: [RegistrationOptions, PLATFORM_ID]
deps: [SwRegistrationOptions, PLATFORM_ID]
}
]
});
Expand All @@ -80,11 +80,11 @@ import {async_fit, async_it} from './async';
TestBed.configureTestingModule({
providers: [
{provide: PLATFORM_ID, useValue: 'browser'},
{provide: RegistrationOptions, useValue: {enabled: true}},
{provide: SwRegistrationOptions, useValue: {enabled: true}},
{
provide: NgswCommChannel,
useFactory: ngswCommChannelFactory,
deps: [RegistrationOptions, PLATFORM_ID],
deps: [SwRegistrationOptions, PLATFORM_ID],
},
],
});
Expand All @@ -110,10 +110,10 @@ import {async_fit, async_it} from './async';
TestBed.configureTestingModule({
providers: [
{provide: PLATFORM_ID, useValue: 'browser'},
{provide: RegistrationOptions, useValue: {enabled: true}}, {
{provide: SwRegistrationOptions, useValue: {enabled: true}}, {
provide: NgswCommChannel,
useFactory: ngswCommChannelFactory,
deps: [RegistrationOptions, PLATFORM_ID]
deps: [SwRegistrationOptions, PLATFORM_ID]
}
]
});
Expand Down
Loading