Skip to content

Commit

Permalink
fix(@angular-devkit/build-angular): fix service worker assets paths
Browse files Browse the repository at this point in the history
  • Loading branch information
filipesilva authored and sylvaindumont committed Apr 16, 2018
1 parent 26cea6d commit 1a5b71b
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 14 deletions.
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
// tslint:disable
// TODO: cleanup this file, it's copied as is from Angular CLI.
import { Path, join, normalize, virtualFs, dirname, getSystemPath, tags } from '@angular-devkit/core';
import { Path, join, normalize, virtualFs, dirname, getSystemPath, tags, fragment } from '@angular-devkit/core';
import { Filesystem } from '@angular/service-worker/config';
import * as crypto from 'crypto';
import * as fs from 'fs';
import * as semver from 'semver';

import { resolveProjectModule } from '../require-project-module';
import { map, reduce, switchMap } from "rxjs/operators";
import { Observable, merge, of } from "rxjs";
import { map, reduce, switchMap, concatMap, mergeMap, toArray, tap } from "rxjs/operators";
import { Observable, merge, of, from } from "rxjs";


export const NEW_SW_VERSION = '5.0.0-rc.0';
Expand All @@ -18,7 +18,22 @@ class CliFilesystem implements Filesystem {
constructor(private _host: virtualFs.Host, private base: string) { }

list(path: string): Promise<string[]> {
return this._host.list(this._resolve(path)).toPromise().then(x => x, _err => []);
const recursiveList = (path: Path): Observable<Path> => this._host.list(path).pipe(
// Emit each fragment individually.
concatMap(fragments => from(fragments)),
// Join the path with fragment.
map(fragment => join(path, fragment)),
// Emit directory content paths instead of the directory path.
mergeMap(path => this._host.isDirectory(path).pipe(
concatMap(isDir => isDir ? recursiveList(path) : of(path))
)
),
);

return recursiveList(this._resolve(path)).pipe(
map(path => path.replace(this.base, '')),
toArray(),
).toPromise().then(x => x, _err => []);
}

read(path: string): Promise<string> {
Expand Down
3 changes: 3 additions & 0 deletions packages/angular_devkit/build_angular/src/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import {
import { BuildWebpackServerSchema } from './schema';
const webpackMerge = require('webpack-merge');

import { addFileReplacements } from '../utils';

export class ServerBuilder implements Builder<BuildWebpackServerSchema> {

Expand All @@ -46,12 +47,14 @@ export class ServerBuilder implements Builder<BuildWebpackServerSchema> {
const options = builderConfig.options;
const root = this.context.workspace.root;
const projectRoot = resolve(root, builderConfig.root);
const host = new virtualFs.AliasHost(this.context.host as virtualFs.Host<Stats>);

// TODO: verify using of(null) to kickstart things is a pattern.
return of(null).pipe(
concatMap(() => options.deleteOutputPath
? this._deleteOutputDir(root, normalize(options.outputPath))
: of(null)),
concatMap(() => addFileReplacements(root, host, options.fileReplacements)),
concatMap(() => new Observable(obs => {
// Ensure Build Optimizer is only used with AOT.
let webpackConfig;
Expand Down
4 changes: 2 additions & 2 deletions packages/angular_devkit/build_angular/src/server/schema.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,9 @@ export interface BuildWebpackServerSchema {
*/
lazyModules?: string[];
/**
* Defines the build environment.
* Replace files with other files in the build.
*/
environment?: string;
fileReplacements: FileReplacements[];
/**
* Define the output filename cache-busting hashing mode.
*/
Expand Down
46 changes: 41 additions & 5 deletions packages/angular_devkit/build_angular/src/server/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,13 @@
"description": "Defines the optimization level of the build.",
"default": false
},
"environment": {
"type": "string",
"description": "Defines the build environment."
"fileReplacements": {
"description": "Replace files with other files in the build.",
"type": "array",
"items": {
"$ref": "#/definitions/fileReplacement"
},
"default": []
},
"outputPath": {
"type": "string",
Expand Down Expand Up @@ -155,5 +159,37 @@
"outputPath",
"main",
"tsConfig"
]
}
],
"definitions": {
"fileReplacement": {
"oneOf": [
{
"type": "object",
"properties": {
"src": {
"type": "string"
},
"replaceWith": {
"type": "string"
}
},
"additionalProperties": false,
"required": ["src", "replaceWith"]
},
{
"type": "object",
"properties": {
"replace": {
"type": "string"
},
"with": {
"type": "string"
}
},
"additionalProperties": false,
"required": ["replace", "with"]
}
]
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,30 +53,97 @@ describe('Browser Builder', () => {
it('works with service worker', (done) => {
host.writeMultipleFiles({
'src/ngsw-config.json': JSON.stringify(manifest),
'src/assets/folder-asset.txt': 'folder-asset.txt',
});

const overrides = { serviceWorker: true };
runTargetSpec(host, browserTargetSpec, overrides).pipe(
tap(buildEvent => {
expect(buildEvent.success).toBe(true);
expect(host.scopedSync().exists(normalize('dist/ngsw.json')));
const ngswJson = JSON.parse(virtualFs.fileBufferToString(
host.scopedSync().read(normalize('dist/ngsw.json'))));
// Verify index and assets are there.
expect(ngswJson).toEqual({
configVersion: 1,
index: '/index.html',
assetGroups: [
{
name: 'app',
installMode: 'prefetch',
updateMode: 'prefetch',
urls: [
'/favicon.ico',
'/index.html',
],
patterns: [],
},
{
name: 'assets',
installMode: 'lazy',
updateMode: 'prefetch',
urls: [
'/assets/folder-asset.txt',
],
patterns: [],
},
],
dataGroups: [],
hashTable: {
'/favicon.ico': '460fcbd48b20fcc32b184388606af1238c890dba',
'/assets/folder-asset.txt': '617f202968a6a81050aa617c2e28e1dca11ce8d4',
'/index.html': '3e659d6e536916b7d178d02a2e6e5492f868bf68',
},
});
}),
).subscribe(undefined, done.fail, done);
}, Timeout.Basic);

it('works with service worker and baseHref', (done) => {
host.writeMultipleFiles({
'src/ngsw-config.json': JSON.stringify(manifest),
'src/assets/folder-asset.txt': 'folder-asset.txt',
});

const overrides = { serviceWorker: true, baseHref: '/foo/bar' };
runTargetSpec(host, browserTargetSpec, overrides).pipe(
tap(buildEvent => {
expect(buildEvent.success).toBe(true);
expect(host.scopedSync().exists(normalize('dist/ngsw.json')));
expect(virtualFs.fileBufferToString(
host.scopedSync().read(normalize('dist/ngsw.json')),
)).toMatch(/"\/foo\/bar\/index.html"/);
const ngswJson = JSON.parse(virtualFs.fileBufferToString(
host.scopedSync().read(normalize('dist/ngsw.json'))));
// Verify index and assets include the base href.
expect(ngswJson).toEqual({
configVersion: 1,
index: '/foo/bar/index.html',
assetGroups: [
{
name: 'app',
installMode: 'prefetch',
updateMode: 'prefetch',
urls: [
'/foo/bar/favicon.ico',
'/foo/bar/index.html',
],
patterns: [],
},
{
name: 'assets',
installMode: 'lazy',
updateMode: 'prefetch',
urls: [
'/foo/bar/assets/folder-asset.txt',
],
patterns: [],
},
],
dataGroups: [],
hashTable: {
'/foo/bar/favicon.ico': '460fcbd48b20fcc32b184388606af1238c890dba',
'/foo/bar/assets/folder-asset.txt': '617f202968a6a81050aa617c2e28e1dca11ce8d4',
'/foo/bar/index.html': '5b53fa9e07e4111b8ef84613fb989a56fee502b0',
},
});
}),
).subscribe(undefined, done.fail, done);
}, Timeout.Basic);
Expand Down

0 comments on commit 1a5b71b

Please sign in to comment.