Skip to content

Commit

Permalink
feat(service-worker): introduce the @angular/service-worker package
Browse files Browse the repository at this point in the history
This service worker is a conceptual derivative of the existing @angular/service-worker maintained at github.com/angular/mobile-toolkit, but has been rewritten to support use across a much wider variety of applications.

Entrypoints include:

@angular/service-worker: a library for use within Angular client apps to communicate with the service worker.
@angular/service-worker/gen: a library for generating ngsw.json files from glob-based SW config files.
@angular/service-worker/ngsw-worker.js: the bundled service worker script itself.
@angular/service-worker/ngsw-cli.js: a CLI tool for generating ngsw.json files from glob-based SW config files.
  • Loading branch information
alxhub committed Sep 28, 2017
1 parent 8dbe2af commit bd4a36b
Show file tree
Hide file tree
Showing 66 changed files with 6,742 additions and 7 deletions.
9 changes: 8 additions & 1 deletion build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ PACKAGES=(core
router
compiler-cli
language-service
benchpress)
benchpress
service-worker)

TSC_PACKAGES=(compiler-cli
language-service
Expand Down Expand Up @@ -235,6 +236,7 @@ compilePackage() {
fi
fi

# Build subpackages
for DIR in ${1}/* ; do
[ -d "${DIR}" ] || continue
BASE_DIR=$(basename "${DIR}")
Expand Down Expand Up @@ -465,6 +467,11 @@ do
addBanners ${BUNDLES_DIR}
minify ${BUNDLES_DIR}

if [[ -e ${SRC_DIR}/build.sh ]]; then
echo "====== Custom build for ${PACKAGE}"
cd ${SRC_DIR} && ${SRC_DIR}/build.sh
fi

) 2>&1 | grep -v "as external dependency"

if [[ ${PACKAGE} == "common" ]]; then
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
},
"dependencies": {
"core-js": "^2.4.1",
"glob-to-regexp": "^0.3.0",
"reflect-metadata": "^0.1.3",
"rxjs": "5.x",
"tslib": "^1.7.1",
Expand Down
17 changes: 17 additions & 0 deletions packages/service-worker/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/bin/bash

set -u -e -o pipefail

BIN=$(cd .. && npm bin)

$BIN/tsc -p worker/tsconfig.json
$BIN/rollup -c worker/rollup-worker.config.js


$BIN/tsc -p cli/tsconfig.json
$BIN/rollup -c cli/rollup-cli.config.js

echo "#!/usr/bin/env node" > ../../dist/packages-dist/service-worker/ngsw-config.js

cat ../../dist/packages-dist/service-worker/ngsw-config-tmp.js >> ../../dist/packages-dist/service-worker/ngsw-config.js
rm ../../dist/packages-dist/service-worker/ngsw-config-tmp.js
42 changes: 42 additions & 0 deletions packages/service-worker/cli/filesystem.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
* @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 {Filesystem} from '@angular/service-worker/config';

const fs = require('fs');
const path = require('path');

export class NodeFilesystem implements Filesystem {
constructor(private base: string) {}

async list(_path: string): Promise<string[]> {
const dir = this.canonical(_path);
const entries = fs.readdirSync(dir).map(
(entry: string) => ({entry, stats: fs.statSync(path.join(dir, entry))}));
const files = entries.filter((entry: any) => !entry.stats.isDirectory())
.map((entry: any) => path.join(_path, entry.entry));

return entries.filter((entry: any) => entry.stats.isDirectory())
.map((entry: any) => path.join(_path, entry.entry))
.reduce(
async(list: string[], subdir: string) => (await list).concat(await this.list(subdir)),
Promise.resolve(files));
}

async read(_path: string): Promise<string> {
const file = this.canonical(_path);
return fs.readFileSync(file).toString();
}

async write(_path: string, contents: string): Promise<void> {
const file = this.canonical(_path);
fs.writeFileSync(file, contents);
}

private canonical(_path: string): string { return path.join(this.base, _path); }
}
29 changes: 29 additions & 0 deletions packages/service-worker/cli/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**
* @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 {Generator, NgswConfig} = require('@angular/service-worker/config');
const fs = require('fs');
const path = require('path');
import {NodeFilesystem} from './filesystem';


const cwd = process.cwd();

const distDir = path.join(cwd, process.argv[2]);
const config = path.join(cwd, process.argv[3]);
const baseHref = process.argv[4] || '/';

const configParsed = JSON.parse(fs.readFileSync(config).toString());

const filesystem = new NodeFilesystem(distDir);
const gen = new Generator(filesystem, baseHref);

(async() => {
const control = await gen.process(configParsed);
await filesystem.write('/ngsw.json', JSON.stringify(control, null, 2));
})();
21 changes: 21 additions & 0 deletions packages/service-worker/cli/rollup-cli.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* @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 resolve from 'rollup-plugin-node-resolve';

export default {
entry: '../../dist/all/@angular/service-worker/cli-custom/main.js',
dest: '../../dist/packages-dist/service-worker/ngsw-config-tmp.js',
format: 'iife',
plugins: [resolve()],
external: [
'fs',
'path',
'@angular/service-worker/config',
],
};
25 changes: 25 additions & 0 deletions packages/service-worker/cli/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"compilerOptions": {
"baseUrl": ".",
"declaration": false,
"strict": true,
"module": "es2015",
"moduleResolution": "node",
"strictNullChecks": true,
"outDir": "../../../dist/all/@angular/service-worker/cli-custom",
"noImplicitAny": true,
"noFallthroughCasesInSwitch": true,
"rootDir": ".",
"paths": {
"@angular/service-worker/config": ["../../../dist/packages/service-worker/config"]
},
"inlineSourceMap": true,
"lib": ["es2015"],
"target": "es5",
"typeRoots": []
},
"files": [
"main.ts",
"../../../node_modules/@types/node/index.d.ts"
]
}
14 changes: 14 additions & 0 deletions packages/service-worker/config/index.ts
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
*/

// This file is not used to build this module. It is only used during editing
// by the TypeScript language service and during build for verification. `ngc`
// replaces this file with production index.ts when it rewrites private symbol
// names.

export * from './public_api';
7 changes: 7 additions & 0 deletions packages/service-worker/config/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"name": "@angular/service-worker/config",
"typings": "./index.d.ts",
"main": "../bundles/service-worker-config.umd.js",
"module": "../esm5/config/index.js",
"es2015": "../esm15/config/index.js"
}
11 changes: 11 additions & 0 deletions packages/service-worker/config/public_api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* @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
*/

export {Filesystem} from './src/filesystem';
export {Generator} from './src/generator';
export {AssetGroup, DataGroup, Duration, Glob, NgswConfig} from './src/in';
23 changes: 23 additions & 0 deletions packages/service-worker/config/rollup.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* @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 resolve from 'rollup-plugin-node-resolve';
import sourcemaps from 'rollup-plugin-sourcemaps';

const globals = {};

export default {
entry: '../../../dist/packages-dist/service-worker/esm5/config.js',
dest: '../../../dist/packages-dist/service-worker/bundles/service-worker-config.umd.js',
format: 'umd',
exports: 'named',
moduleName: 'ng.serviceWorker.config',
plugins: [resolve(), sourcemaps()],
external: Object.keys(globals),
globals: globals
};
48 changes: 48 additions & 0 deletions packages/service-worker/config/src/duration.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/**
* @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 PARSE_TO_PAIRS = /([0-9]+[^0-9]+)/g;
const PAIR_SPLIT = /^([0-9]+)([dhmsu]+)$/;

export function parseDurationToMs(duration: string): number {
const matches: string[] = [];

let array: RegExpExecArray|null;
while ((array = PARSE_TO_PAIRS.exec(duration)) !== null) {
matches.push(array[0]);
}
return matches
.map(match => {
const res = PAIR_SPLIT.exec(match);
if (res === null) {
throw new Error(`Not a valid duration: ${match}`);
}
let factor: number = 0;
switch (res[2]) {
case 'd':
factor = 86400000;
break;
case 'h':
factor = 3600000;
break;
case 'm':
factor = 60000;
break;
case 's':
factor = 1000;
break;
case 'u':
factor = 1;
break;
default:
throw new Error(`Not a valid duration unit: ${res[2]}`);
}
return parseInt(res[1]) * factor;
})
.reduce((total, value) => total + value, 0);
}
19 changes: 19 additions & 0 deletions packages/service-worker/config/src/filesystem.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/**
* @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
*/

/**
* An abstraction over a virtual file system used to enable testing and operation
* of the config generator in different environments.
*
* @experimental
*/
export interface Filesystem {
list(dir: string): Promise<string[]>;
read(file: string): Promise<string>;
write(file: string, contents: string): Promise<void>;
}
Loading

0 comments on commit bd4a36b

Please sign in to comment.