Skip to content

Commit a5fc020

Browse files
clydindgp1130
authored andcommitted
fix(@angular/build): watch all related files during a Sass error
When `dart-sass` returns an error, the provided location span may not be the exact location of the error but can instead be the location of the `@error` call within a Sass function. The generated stack trace string does contain all files related to the error including the usage site in the case of the function `@error` case. To ensure all related files for the error are watched and allow for a rebuild that may correct the error, the stack trace is parsed and found files are added to the watch list. Unfortunately, `dart-sass` does not provide the list directly. If that changes in the future, the stack trace parsing could be removed.
1 parent 22e05dc commit a5fc020

File tree

1 file changed

+32
-1
lines changed

1 file changed

+32
-1
lines changed

packages/angular/build/src/tools/esbuild/stylesheets/sass-language.ts

+32-1
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,11 @@ async function compileString(
174174
if (isSassException(error)) {
175175
const fileWithError = error.span.url ? fileURLToPath(error.span.url) : undefined;
176176

177+
const watchFiles = [filePath, ...extractFilesFromStack(error.sassStack)];
178+
if (fileWithError) {
179+
watchFiles.push(fileWithError);
180+
}
181+
177182
return {
178183
loader: 'css',
179184
errors: [
@@ -182,7 +187,7 @@ async function compileString(
182187
},
183188
],
184189
warnings,
185-
watchFiles: fileWithError ? [filePath, fileWithError] : [filePath],
190+
watchFiles,
186191
};
187192
}
188193

@@ -202,3 +207,29 @@ function sourceMapToUrlComment(
202207

203208
return `/*# sourceMappingURL=data:application/json;charset=utf-8;base64,${urlSourceMap} */`;
204209
}
210+
211+
function* extractFilesFromStack(stack: string): Iterable<string> {
212+
const lines = stack.split('\n');
213+
const cwd = process.cwd();
214+
215+
// Stack line has format of "<file> <location> <identifier>"
216+
for (const line of lines) {
217+
const segments = line.split(' ');
218+
if (segments.length < 3) {
219+
break;
220+
}
221+
222+
// Extract path from stack line.
223+
// Paths may contain spaces. All segments before location are part of the file path.
224+
let path = '';
225+
let index = 0;
226+
while (!segments[index].match(/\d+:\d+/)) {
227+
path += segments[index++];
228+
}
229+
230+
if (path) {
231+
// Stack paths from dart-sass are relative to the current working directory (not input file or workspace root)
232+
yield join(cwd, path);
233+
}
234+
}
235+
}

0 commit comments

Comments
 (0)