Skip to content

Commit 1a5b71b

Browse files
filipesilvasylvaindumont
authored andcommitted
fix(@angular-devkit/build-angular): fix service worker assets paths
Fix angular/angular-cli#10297
1 parent 26cea6d commit 1a5b71b

File tree

5 files changed

+135
-14
lines changed

5 files changed

+135
-14
lines changed

packages/angular_devkit/build_angular/src/angular-cli-files/utilities/service-worker/index.ts

+19-4
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
// tslint:disable
22
// TODO: cleanup this file, it's copied as is from Angular CLI.
3-
import { Path, join, normalize, virtualFs, dirname, getSystemPath, tags } from '@angular-devkit/core';
3+
import { Path, join, normalize, virtualFs, dirname, getSystemPath, tags, fragment } from '@angular-devkit/core';
44
import { Filesystem } from '@angular/service-worker/config';
55
import * as crypto from 'crypto';
66
import * as fs from 'fs';
77
import * as semver from 'semver';
88

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

1313

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

2020
list(path: string): Promise<string[]> {
21-
return this._host.list(this._resolve(path)).toPromise().then(x => x, _err => []);
21+
const recursiveList = (path: Path): Observable<Path> => this._host.list(path).pipe(
22+
// Emit each fragment individually.
23+
concatMap(fragments => from(fragments)),
24+
// Join the path with fragment.
25+
map(fragment => join(path, fragment)),
26+
// Emit directory content paths instead of the directory path.
27+
mergeMap(path => this._host.isDirectory(path).pipe(
28+
concatMap(isDir => isDir ? recursiveList(path) : of(path))
29+
)
30+
),
31+
);
32+
33+
return recursiveList(this._resolve(path)).pipe(
34+
map(path => path.replace(this.base, '')),
35+
toArray(),
36+
).toPromise().then(x => x, _err => []);
2237
}
2338

2439
read(path: string): Promise<string> {

packages/angular_devkit/build_angular/src/server/index.ts

+3
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import {
3737
import { BuildWebpackServerSchema } from './schema';
3838
const webpackMerge = require('webpack-merge');
3939

40+
import { addFileReplacements } from '../utils';
4041

4142
export class ServerBuilder implements Builder<BuildWebpackServerSchema> {
4243

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

5052
// TODO: verify using of(null) to kickstart things is a pattern.
5153
return of(null).pipe(
5254
concatMap(() => options.deleteOutputPath
5355
? this._deleteOutputDir(root, normalize(options.outputPath))
5456
: of(null)),
57+
concatMap(() => addFileReplacements(root, host, options.fileReplacements)),
5558
concatMap(() => new Observable(obs => {
5659
// Ensure Build Optimizer is only used with AOT.
5760
let webpackConfig;

packages/angular_devkit/build_angular/src/server/schema.d.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,9 @@ export interface BuildWebpackServerSchema {
7070
*/
7171
lazyModules?: string[];
7272
/**
73-
* Defines the build environment.
73+
* Replace files with other files in the build.
7474
*/
75-
environment?: string;
75+
fileReplacements: FileReplacements[];
7676
/**
7777
* Define the output filename cache-busting hashing mode.
7878
*/

packages/angular_devkit/build_angular/src/server/schema.json

+41-5
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,13 @@
3232
"description": "Defines the optimization level of the build.",
3333
"default": false
3434
},
35-
"environment": {
36-
"type": "string",
37-
"description": "Defines the build environment."
35+
"fileReplacements": {
36+
"description": "Replace files with other files in the build.",
37+
"type": "array",
38+
"items": {
39+
"$ref": "#/definitions/fileReplacement"
40+
},
41+
"default": []
3842
},
3943
"outputPath": {
4044
"type": "string",
@@ -155,5 +159,37 @@
155159
"outputPath",
156160
"main",
157161
"tsConfig"
158-
]
159-
}
162+
],
163+
"definitions": {
164+
"fileReplacement": {
165+
"oneOf": [
166+
{
167+
"type": "object",
168+
"properties": {
169+
"src": {
170+
"type": "string"
171+
},
172+
"replaceWith": {
173+
"type": "string"
174+
}
175+
},
176+
"additionalProperties": false,
177+
"required": ["src", "replaceWith"]
178+
},
179+
{
180+
"type": "object",
181+
"properties": {
182+
"replace": {
183+
"type": "string"
184+
},
185+
"with": {
186+
"type": "string"
187+
}
188+
},
189+
"additionalProperties": false,
190+
"required": ["replace", "with"]
191+
}
192+
]
193+
}
194+
}
195+
}

packages/angular_devkit/build_angular/test/browser/service-worker_spec_large.ts

+70-3
Original file line numberDiff line numberDiff line change
@@ -53,30 +53,97 @@ describe('Browser Builder', () => {
5353
it('works with service worker', (done) => {
5454
host.writeMultipleFiles({
5555
'src/ngsw-config.json': JSON.stringify(manifest),
56+
'src/assets/folder-asset.txt': 'folder-asset.txt',
5657
});
5758

5859
const overrides = { serviceWorker: true };
5960
runTargetSpec(host, browserTargetSpec, overrides).pipe(
6061
tap(buildEvent => {
6162
expect(buildEvent.success).toBe(true);
6263
expect(host.scopedSync().exists(normalize('dist/ngsw.json')));
64+
const ngswJson = JSON.parse(virtualFs.fileBufferToString(
65+
host.scopedSync().read(normalize('dist/ngsw.json'))));
66+
// Verify index and assets are there.
67+
expect(ngswJson).toEqual({
68+
configVersion: 1,
69+
index: '/index.html',
70+
assetGroups: [
71+
{
72+
name: 'app',
73+
installMode: 'prefetch',
74+
updateMode: 'prefetch',
75+
urls: [
76+
'/favicon.ico',
77+
'/index.html',
78+
],
79+
patterns: [],
80+
},
81+
{
82+
name: 'assets',
83+
installMode: 'lazy',
84+
updateMode: 'prefetch',
85+
urls: [
86+
'/assets/folder-asset.txt',
87+
],
88+
patterns: [],
89+
},
90+
],
91+
dataGroups: [],
92+
hashTable: {
93+
'/favicon.ico': '460fcbd48b20fcc32b184388606af1238c890dba',
94+
'/assets/folder-asset.txt': '617f202968a6a81050aa617c2e28e1dca11ce8d4',
95+
'/index.html': '3e659d6e536916b7d178d02a2e6e5492f868bf68',
96+
},
97+
});
6398
}),
6499
).subscribe(undefined, done.fail, done);
65100
}, Timeout.Basic);
66101

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

72108
const overrides = { serviceWorker: true, baseHref: '/foo/bar' };
73109
runTargetSpec(host, browserTargetSpec, overrides).pipe(
74110
tap(buildEvent => {
75111
expect(buildEvent.success).toBe(true);
76112
expect(host.scopedSync().exists(normalize('dist/ngsw.json')));
77-
expect(virtualFs.fileBufferToString(
78-
host.scopedSync().read(normalize('dist/ngsw.json')),
79-
)).toMatch(/"\/foo\/bar\/index.html"/);
113+
const ngswJson = JSON.parse(virtualFs.fileBufferToString(
114+
host.scopedSync().read(normalize('dist/ngsw.json'))));
115+
// Verify index and assets include the base href.
116+
expect(ngswJson).toEqual({
117+
configVersion: 1,
118+
index: '/foo/bar/index.html',
119+
assetGroups: [
120+
{
121+
name: 'app',
122+
installMode: 'prefetch',
123+
updateMode: 'prefetch',
124+
urls: [
125+
'/foo/bar/favicon.ico',
126+
'/foo/bar/index.html',
127+
],
128+
patterns: [],
129+
},
130+
{
131+
name: 'assets',
132+
installMode: 'lazy',
133+
updateMode: 'prefetch',
134+
urls: [
135+
'/foo/bar/assets/folder-asset.txt',
136+
],
137+
patterns: [],
138+
},
139+
],
140+
dataGroups: [],
141+
hashTable: {
142+
'/foo/bar/favicon.ico': '460fcbd48b20fcc32b184388606af1238c890dba',
143+
'/foo/bar/assets/folder-asset.txt': '617f202968a6a81050aa617c2e28e1dca11ce8d4',
144+
'/foo/bar/index.html': '5b53fa9e07e4111b8ef84613fb989a56fee502b0',
145+
},
146+
});
80147
}),
81148
).subscribe(undefined, done.fail, done);
82149
}, Timeout.Basic);

0 commit comments

Comments
 (0)