Skip to content

Commit 2f92121

Browse files
committed
fix(@angular/build): add asset tracking to application builder watch files
This commit updates the application builder to include assets in the watch process, triggering file re-copying when changes are detected. Closes angular#28415
1 parent ef3dc2e commit 2f92121

File tree

2 files changed

+77
-10
lines changed

2 files changed

+77
-10
lines changed
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.dev/license
7+
*/
8+
9+
import { concatMap, count, take, timeout } from 'rxjs';
10+
import { buildApplication } from '../../index';
11+
import { APPLICATION_BUILDER_INFO, BASE_OPTIONS, describeBuilder } from '../setup';
12+
13+
/**
14+
* Maximum time in milliseconds for single build/rebuild
15+
* This accounts for CI variability.
16+
*/
17+
const BUILD_TIMEOUT = 10_000;
18+
19+
describeBuilder(buildApplication, APPLICATION_BUILDER_INFO, (harness) => {
20+
describe('Behavior: "Rebuilds when input asset changes"', () => {
21+
beforeEach(async () => {
22+
// Application code is not needed for styles tests
23+
await harness.writeFile('src/main.ts', 'console.log("TEST");');
24+
await harness.writeFile('public/asset.txt', 'foo');
25+
});
26+
27+
it('emits updated asset', async () => {
28+
harness.useTarget('build', {
29+
...BASE_OPTIONS,
30+
assets: [
31+
{
32+
glob: '**/*',
33+
input: 'public',
34+
},
35+
],
36+
watch: true,
37+
});
38+
39+
const buildCount = await harness
40+
.execute({ outputLogsOnFailure: false })
41+
.pipe(
42+
timeout(BUILD_TIMEOUT),
43+
concatMap(async ({ result }, index) => {
44+
switch (index) {
45+
case 0:
46+
expect(result?.success).toBeTrue();
47+
harness.expectFile('dist/browser/asset.txt').content.toContain('foo');
48+
49+
await harness.writeFile('public/asset.txt', 'bar');
50+
break;
51+
case 1:
52+
expect(result?.success).toBeTrue();
53+
harness.expectFile('dist/browser/asset.txt').content.toContain('bar');
54+
break;
55+
}
56+
}),
57+
take(2),
58+
count(),
59+
)
60+
.toPromise();
61+
62+
expect(buildCount).toBe(2);
63+
});
64+
});
65+
});

packages/angular/build/src/tools/esbuild/bundler-execution-result.ts

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -147,18 +147,20 @@ export class ExecutionResult {
147147
};
148148
}
149149

150-
get watchFiles() {
151-
// Bundler contexts internally normalize file dependencies
152-
const files = this.rebuildContexts.typescriptContexts
153-
.flatMap((context) => [...context.watchFiles])
154-
.concat(this.rebuildContexts.otherContexts.flatMap((context) => [...context.watchFiles]));
155-
if (this.codeBundleCache?.referencedFiles) {
150+
get watchFiles(): Readonly<string[]> {
151+
const { typescriptContexts, otherContexts } = this.rebuildContexts;
152+
153+
return [
154+
// Bundler contexts internally normalize file dependencies.
155+
...typescriptContexts.flatMap((context) => [...context.watchFiles]),
156+
...otherContexts.flatMap((context) => [...context.watchFiles]),
156157
// These files originate from TS/NG and can have POSIX path separators even on Windows.
157158
// To ensure path comparisons are valid, all these paths must be normalized.
158-
files.push(...this.codeBundleCache.referencedFiles.map(normalize));
159-
}
160-
161-
return files.concat(this.extraWatchFiles);
159+
...(this.codeBundleCache?.referencedFiles?.map(normalize) ?? []),
160+
// The assets source files.
161+
...this.assetFiles.map(({ source }) => source),
162+
...this.extraWatchFiles,
163+
];
162164
}
163165

164166
createRebuildState(fileChanges: ChangedFiles): RebuildState {

0 commit comments

Comments
 (0)