Skip to content

Commit 8ff0ea1

Browse files
committed
fix(@angular/build): ensure transitive SCSS partial errors are tracked in watch mode
When stylesheet bundling fails due to an error in a SCSS partial, we now ensure that `referencedFiles` are still passed to the `FileReferenceTracker`. This prevents the dependency between the component and the error file from being lost, allowing the component to be correctly rebuilt when the error is fixed.
1 parent f1ed025 commit 8ff0ea1

File tree

2 files changed

+89
-0
lines changed

2 files changed

+89
-0
lines changed

packages/angular/build/src/builders/application/tests/behavior/rebuild-component_styles_spec.ts

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,5 +58,85 @@ describeBuilder(buildApplication, APPLICATION_BUILDER_INFO, (harness) => {
5858
]);
5959
});
6060
}
61+
62+
it('rebuilds component after error on rebuild from transitive import', async () => {
63+
harness.useTarget('build', {
64+
...BASE_OPTIONS,
65+
watch: true,
66+
});
67+
68+
await harness.modifyFile('src/app/app.component.ts', (content) =>
69+
content.replace('app.component.css', 'app.component.scss'),
70+
);
71+
await harness.writeFile('src/app/app.component.scss', "@import './a';");
72+
await harness.writeFile('src/app/a.scss', '$primary: aqua;\\nh1 { color: $primary; }');
73+
74+
await harness.executeWithCases([
75+
async ({ result }) => {
76+
expect(result?.success).toBe(true);
77+
78+
harness.expectFile('dist/browser/main.js').content.toContain('color: aqua');
79+
80+
// Introduce a syntax error
81+
await harness.writeFile(
82+
'src/app/a.scss',
83+
'invalid-invalid-invalid\\nh1 { color: $primary; }',
84+
);
85+
},
86+
async ({ result }) => {
87+
expect(result?.success).toBe(false);
88+
89+
// Fix the syntax error
90+
await harness.writeFile('src/app/a.scss', '$primary: blue;\\nh1 { color: $primary; }');
91+
},
92+
({ result }) => {
93+
expect(result?.success).toBe(true);
94+
95+
harness.expectFile('dist/browser/main.js').content.toContain('color: blue');
96+
},
97+
]);
98+
});
99+
100+
it('rebuilds component after error on rebuild from deep transitive import with partials', async () => {
101+
harness.useTarget('build', {
102+
...BASE_OPTIONS,
103+
watch: true,
104+
});
105+
106+
await harness.modifyFile('src/app/app.component.ts', (content) =>
107+
content.replace('app.component.css', 'app.component.scss'),
108+
);
109+
await harness.writeFile('src/app/app.component.scss', "@import './intermediary';");
110+
await harness.writeFile('src/app/_intermediary.scss', "@import './partial';");
111+
await harness.writeFile('src/app/_partial.scss', '$primary: aqua;\\nh1 { color: $primary; }');
112+
113+
await harness.executeWithCases([
114+
async ({ result }) => {
115+
expect(result?.success).toBe(true);
116+
117+
harness.expectFile('dist/browser/main.js').content.toContain('color: aqua');
118+
119+
// Introduce a syntax error deeply
120+
await harness.writeFile(
121+
'src/app/_partial.scss',
122+
'invalid-invalid-invalid\\nh1 { color: $primary; }',
123+
);
124+
},
125+
async ({ result }) => {
126+
expect(result?.success).toBe(false);
127+
128+
// Fix the syntax error deeply
129+
await harness.writeFile(
130+
'src/app/_partial.scss',
131+
'$primary: blue;\\nh1 { color: $primary; }',
132+
);
133+
},
134+
({ result }) => {
135+
expect(result?.success).toBe(true);
136+
137+
harness.expectFile('dist/browser/main.js').content.toContain('color: blue');
138+
},
139+
]);
140+
});
61141
});
62142
});

packages/angular/build/src/tools/esbuild/angular/compiler-plugin.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,10 +220,19 @@ export function createCompilerPlugin(
220220
if (stylesheetResult.errors) {
221221
(result.errors ??= []).push(...stylesheetResult.errors);
222222

223+
const { referencedFiles } = stylesheetResult;
224+
if (referencedFiles) {
225+
referencedFileTracker.add(containingFile, referencedFiles);
226+
if (stylesheetFile) {
227+
referencedFileTracker.add(stylesheetFile, referencedFiles);
228+
}
229+
}
230+
223231
return '';
224232
}
225233

226234
const { contents, outputFiles, metafile, referencedFiles } = stylesheetResult;
235+
227236
additionalResults.set(resultSource, {
228237
outputFiles,
229238
metafile,

0 commit comments

Comments
 (0)