Skip to content

Commit 3394d3c

Browse files
committed
fix(@angular-devkit/build-angular): ensure all related stylesheets are rebuilt when an import changes
This fixes a logic error wherein some stylesheets could potentially not be rebuilt if a shared import was edited and triggered an application rebuild. (cherry picked from commit ce2c3ef)
1 parent ca18ead commit 3394d3c

File tree

2 files changed

+62
-5
lines changed

2 files changed

+62
-5
lines changed

packages/angular_devkit/build_angular/src/builders/application/tests/behavior/rebuild-global_styles_spec.ts

+55
Original file line numberDiff line numberDiff line change
@@ -112,5 +112,60 @@ describeBuilder(buildApplication, APPLICATION_BUILDER_INFO, (harness) => {
112112

113113
expect(buildCount).toBe(3);
114114
});
115+
116+
it('rebuilds dependent Sass stylesheets after error on initial build from import', async () => {
117+
harness.useTarget('build', {
118+
...BASE_OPTIONS,
119+
watch: true,
120+
styles: [
121+
{ bundleName: 'styles', input: 'src/styles.scss' },
122+
{ bundleName: 'other', input: 'src/other.scss' },
123+
],
124+
});
125+
126+
await harness.writeFile('src/styles.scss', "@import './a';");
127+
await harness.writeFile('src/other.scss', "@import './a'; h1 { color: green; }");
128+
await harness.writeFile('src/a.scss', 'invalid-invalid-invalid\\nh1 { color: $primary; }');
129+
130+
const buildCount = await harness
131+
.execute({ outputLogsOnFailure: false })
132+
.pipe(
133+
timeout(30000),
134+
concatMap(async ({ result }, index) => {
135+
switch (index) {
136+
case 0:
137+
expect(result?.success).toBe(false);
138+
139+
await harness.writeFile('src/a.scss', '$primary: aqua;\\nh1 { color: $primary; }');
140+
break;
141+
case 1:
142+
expect(result?.success).toBe(true);
143+
harness.expectFile('dist/browser/styles.css').content.toContain('color: aqua');
144+
harness.expectFile('dist/browser/styles.css').content.not.toContain('color: blue');
145+
146+
harness.expectFile('dist/browser/other.css').content.toContain('color: green');
147+
harness.expectFile('dist/browser/other.css').content.toContain('color: aqua');
148+
harness.expectFile('dist/browser/other.css').content.not.toContain('color: blue');
149+
150+
await harness.writeFile('src/a.scss', '$primary: blue;\\nh1 { color: $primary; }');
151+
break;
152+
case 2:
153+
expect(result?.success).toBe(true);
154+
harness.expectFile('dist/browser/styles.css').content.not.toContain('color: aqua');
155+
harness.expectFile('dist/browser/styles.css').content.toContain('color: blue');
156+
157+
harness.expectFile('dist/browser/other.css').content.toContain('color: green');
158+
harness.expectFile('dist/browser/other.css').content.not.toContain('color: aqua');
159+
harness.expectFile('dist/browser/other.css').content.toContain('color: blue');
160+
break;
161+
}
162+
}),
163+
take(3),
164+
count(),
165+
)
166+
.toPromise();
167+
168+
expect(buildCount).toBe(3);
169+
});
115170
});
116171
});

packages/angular_devkit/build_angular/src/tools/esbuild/load-result-cache.ts

+7-5
Original file line numberDiff line numberDiff line change
@@ -70,16 +70,18 @@ export class MemoryLoadResultCache implements LoadResultCache {
7070
}
7171

7272
invalidate(path: string): boolean {
73-
const affected = this.#fileDependencies.get(path);
73+
const affectedPaths = this.#fileDependencies.get(path);
7474
let found = false;
7575

76-
if (affected) {
77-
affected.forEach((a) => (found ||= this.#loadResults.delete(a)));
76+
if (affectedPaths) {
77+
for (const affected of affectedPaths) {
78+
if (this.#loadResults.delete(affected)) {
79+
found = true;
80+
}
81+
}
7882
this.#fileDependencies.delete(path);
7983
}
8084

81-
found ||= this.#loadResults.delete(path);
82-
8385
return found;
8486
}
8587

0 commit comments

Comments
 (0)