From de9eae8703418a6e8fd59a63d8194a0463f37a8f Mon Sep 17 00:00:00 2001
From: Alan Agius <17563226+alan-agius4@users.noreply.github.com>
Date: Wed, 21 Oct 2026 16:45:00 +0000
Subject: [PATCH 1/3] fix(@angular/build): improve library compilation
diagnostics and stylesheet reference tracking
- Forward warnings from `compilationInstance.initialize()` into formatted warnings output.
- Run syntactic and option diagnostics (`DiagnosticModes.All & ~DiagnosticModes.Semantic`) when `useTypeChecking` is `false`.
- Run `diagnoseFiles` even when `stylesheetErrors.length > 0` so `AotCompilation` drains `affectedFiles` into `diagnosticCache`, and guard `diagnosePromise` against unhandled rejections.
- Pass `'css'` for inline `
Styled
',
+ 'projects/lib/src/lib/lib.component.ts': `
+ import { Component } from "@angular/core";
+
+ @Component({
+ selector: "lib-html-style",
+ templateUrl: "./lib.component.html",
+ })
+ export class LibComponent {}
+ `,
+ });
+
+ harness.useTarget('build', {
+ ...BASE_OPTIONS,
+ inlineStyleLanguage: InlineStyleLanguage.Sass,
+ });
+
+ const { result } = await harness.executeOnce();
+ expect(result?.success).toBeTrue();
+
+ const fesm = harness.readFile('dist/lib/fesm2022/lib.mjs');
+ expect(fesm).toMatch(/color:\s*#ff5722/);
+ });
});
});
diff --git a/packages/angular/build/src/builders/library/tests/behavior/watch_spec.ts b/packages/angular/build/src/builders/library/tests/behavior/watch_spec.ts
index b648c690951a..e117f8efe9f8 100644
--- a/packages/angular/build/src/builders/library/tests/behavior/watch_spec.ts
+++ b/packages/angular/build/src/builders/library/tests/behavior/watch_spec.ts
@@ -1058,5 +1058,105 @@ describeLibraryBuilder(executeLibraryBuilder, LIBRARY_BUILDER_INFO, (harness) =>
},
]);
});
+
+ it('should preserve template diagnostics across watch rebuilds after a stylesheet error', async () => {
+ await harness.modifyFile('projects/lib/tsconfig.lib.json', (content) => {
+ const tsconfig = JSON.parse(content);
+ tsconfig.angularCompilerOptions = {
+ ...tsconfig.angularCompilerOptions,
+ strictTemplates: true,
+ };
+
+ return JSON.stringify(tsconfig, null, 2);
+ });
+
+ await harness.writeFiles({
+ 'projects/lib/src/lib/other.component.ts': `
+ import { Component } from '@angular/core';
+
+ @Component({
+ selector: 'lib-other',
+ template: '{{ validProp }}',
+ })
+ export class OtherComponent {
+ validProp = 'ok';
+ }
+ `,
+ 'projects/lib/src/lib/lib.component.scss': '.valid { color: blue; }',
+ 'projects/lib/src/lib/lib.component.ts': `
+ import { Component } from '@angular/core';
+
+ @Component({
+ selector: 'lib-primary',
+ template: 'Primary',
+ styleUrl: './lib.component.scss',
+ })
+ export class LibComponent {}
+ `,
+ 'projects/lib/src/public-api.ts': `
+ export * from './lib/lib.component';
+ export * from './lib/other.component';
+ `,
+ });
+
+ harness.useTarget('build', {
+ ...BASE_OPTIONS,
+ watch: true,
+ });
+
+ await harness.executeWithCases([
+ async ({ result }) => {
+ expect(result?.success).toBeTrue();
+
+ // Introduce both a stylesheet error in LibComponent and a template error in OtherComponent
+ await harness.writeFiles({
+ 'projects/lib/src/lib/lib.component.scss': '.broken { color: $undefined_var; }',
+ 'projects/lib/src/lib/other.component.ts': `
+ import { Component } from '@angular/core';
+
+ @Component({
+ selector: 'lib-other',
+ template: '{{ unknownProp }}',
+ })
+ export class OtherComponent {}
+ `,
+ });
+ },
+ async ({ result, logs }) => {
+ expect(result?.success).toBeFalse();
+ expect(logs).toContain(
+ jasmine.objectContaining({
+ level: 'error',
+ message: jasmine.stringContaining('Undefined variable'),
+ }),
+ );
+ expect(logs).toContain(
+ jasmine.objectContaining({
+ level: 'error',
+ message: jasmine.stringContaining(
+ "Property 'unknownProp' does not exist on type 'OtherComponent'",
+ ),
+ }),
+ );
+
+ // Fix only the stylesheet error in LibComponent while OtherComponent still has the template error
+ await harness.writeFile(
+ 'projects/lib/src/lib/lib.component.scss',
+ '.valid { color: green; }',
+ );
+ },
+ ({ result, logs }) => {
+ expect(result?.success).toBeFalse();
+ expect(logs).toContain(
+ jasmine.objectContaining({
+ level: 'error',
+ message: jasmine.stringContaining(
+ "Property 'unknownProp' does not exist on type 'OtherComponent'",
+ ),
+ }),
+ );
+ },
+ ]);
+ });
});
});
From eb6d6df79a6d5cf9beed28ad5e3000e4ba98b4e3 Mon Sep 17 00:00:00 2001
From: Alan Agius <17563226+alan-agius4@users.noreply.github.com>
Date: Thu, 22 Oct 2026 18:14:40 +0000
Subject: [PATCH 2/3] fixup! fix(@angular/build): improve library compilation
diagnostics and stylesheet reference tracking
---
.../builders/library/pipeline/compilation.ts | 64 +++++++++++--------
.../library/pipeline/compilation_spec.ts | 1 -
2 files changed, 36 insertions(+), 29 deletions(-)
diff --git a/packages/angular/build/src/builders/library/pipeline/compilation.ts b/packages/angular/build/src/builders/library/pipeline/compilation.ts
index 9aa4691eb13a..2a1adddaee50 100644
--- a/packages/angular/build/src/builders/library/pipeline/compilation.ts
+++ b/packages/angular/build/src/builders/library/pipeline/compilation.ts
@@ -7,7 +7,7 @@
*/
import { type PartialMessage, formatMessages } from 'esbuild';
-import { existsSync } from 'node:fs';
+import { access, constants } from 'node:fs/promises';
import {
type AngularCompilation,
DiagnosticModes,
@@ -172,7 +172,7 @@ export async function compileLibrary(
const esmFiles = cached?.esmFiles ?? new Map();
const dtsFiles = cached?.dtsFiles ?? new Map();
const posixReferencedFiles = new Set(referencedFiles.map(toPosixPath));
- const { changedEsmFiles, changedDtsFiles } = updateEmittedFileCaches(
+ const { changedEsmFiles, changedDtsFiles } = await updateEmittedFileCaches(
emittedFiles,
esmFiles,
dtsFiles,
@@ -216,40 +216,49 @@ export async function compileLibrary(
* @param modifiedFiles Optional set of modified POSIX file paths in incremental builds.
* @returns Sets of changed ESM and DTS file paths.
*/
-function updateEmittedFileCaches(
+async function updateEmittedFileCaches(
emittedFiles: Iterable,
esmFiles: Map,
dtsFiles: Map,
posixReferencedFiles: ReadonlySet,
modifiedFiles?: ReadonlySet,
-): { changedEsmFiles: Set; changedDtsFiles: Set } {
+): Promise<{ changedEsmFiles: Set; changedDtsFiles: Set }> {
const changedEsmFiles = new Set();
const changedDtsFiles = new Set();
- if (modifiedFiles) {
- for (const modifiedFile of modifiedFiles) {
- if (posixReferencedFiles.has(modifiedFile)) {
- continue;
- }
-
- const basePathWithoutExt = modifiedFile.replace(/(?:\.d\.[cm]?ts|\.[cm]?[jt]sx?)$/i, '');
- if (basePathWithoutExt === modifiedFile || existsSync(modifiedFile)) {
- continue;
- }
+ const removalChecks: Promise[] = [];
+ for (const modifiedFile of modifiedFiles ?? []) {
+ if (posixReferencedFiles.has(modifiedFile)) {
+ continue;
+ }
- for (const ext of EMITTED_EXTENSIONS) {
- const outputPath = `${basePathWithoutExt}${ext}`;
- const mapPath = `${outputPath}.map`;
- if (esmFiles.delete(outputPath)) {
- changedEsmFiles.add(outputPath);
- }
- if (dtsFiles.delete(outputPath)) {
- changedDtsFiles.add(outputPath);
- }
- esmFiles.delete(mapPath);
- dtsFiles.delete(mapPath);
- }
+ const basePathWithoutExt = modifiedFile.replace(/(?:\.d\.[cm]?ts|\.[cm]?[jt]sx?)$/i, '');
+ if (basePathWithoutExt === modifiedFile) {
+ continue;
}
+
+ removalChecks.push(
+ access(modifiedFile, constants.F_OK).then(
+ () => {},
+ () => {
+ for (const ext of EMITTED_EXTENSIONS) {
+ const outputPath = `${basePathWithoutExt}${ext}`;
+ const mapPath = `${outputPath}.map`;
+ if (esmFiles.delete(outputPath)) {
+ changedEsmFiles.add(outputPath);
+ }
+ if (dtsFiles.delete(outputPath)) {
+ changedDtsFiles.add(outputPath);
+ }
+ esmFiles.delete(mapPath);
+ dtsFiles.delete(mapPath);
+ }
+ },
+ ),
+ );
+ }
+ if (removalChecks.length > 0) {
+ await Promise.all(removalChecks);
}
for (const { filename, contents } of emittedFiles) {
@@ -301,9 +310,8 @@ async function runDiagnosticsAndFormat(
} catch (error) {
assertIsError(error);
errors.push({
- text: 'Angular compilation diagnostics failed.',
+ text: error.message,
location: null,
- notes: [{ text: error.stack ?? error.message, location: null }],
});
}
diff --git a/packages/angular/build/src/builders/library/pipeline/compilation_spec.ts b/packages/angular/build/src/builders/library/pipeline/compilation_spec.ts
index 802e64c24713..143a73358e57 100644
--- a/packages/angular/build/src/builders/library/pipeline/compilation_spec.ts
+++ b/packages/angular/build/src/builders/library/pipeline/compilation_spec.ts
@@ -212,7 +212,6 @@ describe('compileLibrary pipeline', () => {
const errorsText = state.executionResult.errors.join('\n');
expect(errorsText).toContain('Sass syntax error');
- expect(errorsText).toContain('Angular compilation diagnostics failed.');
expect(errorsText).toContain('Diagnostic crash');
});
From ed5cc15c36681b5b0184736a5adc094ad93fabfd Mon Sep 17 00:00:00 2001
From: Alan Agius <17563226+alan-agius4@users.noreply.github.com>
Date: Thu, 22 Oct 2026 18:21:26 +0000
Subject: [PATCH 3/3] fixup! fix(@angular/build): improve library compilation
diagnostics and stylesheet reference tracking
---
.../angular/build/src/builders/library/pipeline/compilation.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/angular/build/src/builders/library/pipeline/compilation.ts b/packages/angular/build/src/builders/library/pipeline/compilation.ts
index 2a1adddaee50..07dd0665c08a 100644
--- a/packages/angular/build/src/builders/library/pipeline/compilation.ts
+++ b/packages/angular/build/src/builders/library/pipeline/compilation.ts
@@ -214,7 +214,7 @@ export async function compileLibrary(
* @param dtsFiles In-memory map of POSIX declaration file paths to contents.
* @param posixReferencedFiles Set of POSIX file paths currently referenced by the program.
* @param modifiedFiles Optional set of modified POSIX file paths in incremental builds.
- * @returns Sets of changed ESM and DTS file paths.
+ * @returns A promise resolving to the sets of changed ESM and DTS file paths.
*/
async function updateEmittedFileCaches(
emittedFiles: Iterable,