Skip to content

Commit dff4dea

Browse files
committedMay 8, 2024·
fix(@angular/build): ensure recreated files are watched
When deleting a file and then recreating a file that is again referenced in the application, the watch state will now be correctly synchronized. Previously the application builder would consider the previously deleted file as still watched which would prevent it from being watched again. This situation can happen when switching source control branches while a build is active watching. (cherry picked from commit 8cff5e7)
1 parent 9c574c0 commit dff4dea

File tree

2 files changed

+114
-0
lines changed

2 files changed

+114
-0
lines changed
 

Diff for: ‎packages/angular/build/src/builders/application/build-action.ts

+3
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,9 @@ export async function* runEsBuildBuildAction(
180180
logger.info(changes.toDebugString());
181181
}
182182

183+
// Clear removed files from current watch files
184+
changes.removed.forEach((removedPath) => currentWatchFiles.delete(removedPath));
185+
183186
result = await withProgress('Changes detected. Rebuilding...', () =>
184187
action(result.createRebuildState(changes)),
185188
);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
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.io/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+
export const BUILD_TIMEOUT = 30_000;
18+
19+
describeBuilder(buildApplication, APPLICATION_BUILDER_INFO, (harness) => {
20+
describe('Behavior: "Rebuild updates in general cases"', () => {
21+
it('detects changes after a file was deleted and recreated', async () => {
22+
harness.useTarget('build', {
23+
...BASE_OPTIONS,
24+
watch: true,
25+
});
26+
27+
const fileAContent = `
28+
console.log('FILE-A');
29+
export {};
30+
`;
31+
32+
// Create a file and add to application
33+
await harness.writeFile('src/app/file-a.ts', fileAContent);
34+
await harness.writeFile(
35+
'src/app/app.component.ts',
36+
`
37+
import { Component } from '@angular/core';
38+
import './file-a';
39+
@Component({
40+
selector: 'app-root',
41+
template: 'App component',
42+
})
43+
export class AppComponent { }
44+
`,
45+
);
46+
47+
const buildCount = await harness
48+
.execute({ outputLogsOnFailure: false })
49+
.pipe(
50+
timeout(BUILD_TIMEOUT),
51+
concatMap(async ({ result, logs }, index) => {
52+
switch (index) {
53+
case 0:
54+
expect(result?.success).toBeTrue();
55+
harness.expectFile('dist/browser/main.js').content.toContain('FILE-A');
56+
57+
// Delete the imported file
58+
await harness.removeFile('src/app/file-a.ts');
59+
60+
break;
61+
case 1:
62+
// Should fail from missing import
63+
expect(result?.success).toBeFalse();
64+
65+
// Remove the failing import
66+
await harness.modifyFile('src/app/app.component.ts', (content) =>
67+
content.replace(`import './file-a';`, ''),
68+
);
69+
70+
break;
71+
case 2:
72+
expect(result?.success).toBeTrue();
73+
74+
harness.expectFile('dist/browser/main.js').content.not.toContain('FILE-A');
75+
76+
// Recreate the file and the import
77+
await harness.writeFile('src/app/file-a.ts', fileAContent);
78+
await harness.modifyFile(
79+
'src/app/app.component.ts',
80+
(content) => `import './file-a';\n` + content,
81+
);
82+
83+
break;
84+
case 3:
85+
expect(result?.success).toBeTrue();
86+
87+
harness.expectFile('dist/browser/main.js').content.toContain('FILE-A');
88+
89+
// Change the imported file
90+
await harness.modifyFile('src/app/file-a.ts', (content) =>
91+
content.replace('FILE-A', 'FILE-B'),
92+
);
93+
94+
break;
95+
case 4:
96+
expect(result?.success).toBeTrue();
97+
98+
harness.expectFile('dist/browser/main.js').content.toContain('FILE-B');
99+
100+
break;
101+
}
102+
}),
103+
take(5),
104+
count(),
105+
)
106+
.toPromise();
107+
108+
expect(buildCount).toBe(5);
109+
});
110+
});
111+
});

0 commit comments

Comments
 (0)
Please sign in to comment.