From b872a71e3a4e590ee289dea7546f54b7648c8037 Mon Sep 17 00:00:00 2001 From: Charles Lyding <19598772+clydin@users.noreply.github.com> Date: Mon, 31 Aug 2026 13:24:34 -0400 Subject: [PATCH] refactor(@angular/build): move compiler-cli loading to TypeScriptCompilation AngularCompilation serves as the top-level compilation contract used across the build pipeline, including on the main thread via ParallelCompilation. Neither AngularCompilation nor ParallelCompilation requires loading @angular/compiler-cli or reading tsconfig.json configurations. The loadCompilerCli and loadConfiguration methods are now moved to TypeScriptCompilation, which is the base class for in-process TypeScript compilations (AotCompilation and JitCompilation). This completely decouples AngularCompilation from @angular/compiler-cli and ensures that compiler-cli loading and configuration parsing are localized exclusively to the worker compilation hierarchy. --- .../compilation/angular-compilation.ts | 33 ------------------ .../compilation/angular-compilation_spec.ts | 6 ++++ .../angular/compilation/aot-compilation.ts | 7 ++-- .../angular/compilation/jit-compilation.ts | 5 ++- .../compilation/typescript-compilation.ts | 34 ++++++++++++++++++- 5 files changed, 44 insertions(+), 41 deletions(-) diff --git a/packages/angular/build/src/tools/angular/compilation/angular-compilation.ts b/packages/angular/build/src/tools/angular/compilation/angular-compilation.ts index ea1fe00d04aa..6bd836139c5f 100644 --- a/packages/angular/build/src/tools/angular/compilation/angular-compilation.ts +++ b/packages/angular/build/src/tools/angular/compilation/angular-compilation.ts @@ -6,9 +6,7 @@ * found in the LICENSE file at https://angular.dev/license */ -import type * as ng from '@angular/compiler-cli'; import type { PartialMessage } from 'esbuild'; -import { profileSync } from '../../esbuild/profiling'; import type { AngularHostOptions } from '../angular-host'; import type { CompilerOptionOverrides } from './compiler-options'; @@ -50,37 +48,6 @@ export enum DiagnosticModes { } export abstract class AngularCompilation { - static #angularCompilerCliModule?: typeof ng; - - static async loadCompilerCli(): Promise { - AngularCompilation.#angularCompilerCliModule ??= await import('@angular/compiler-cli'); - - return AngularCompilation.#angularCompilerCliModule; - } - - protected async loadConfiguration(tsconfig: string): Promise { - const { readConfiguration } = await AngularCompilation.loadCompilerCli(); - - return profileSync('NG_READ_CONFIG', () => - readConfiguration(tsconfig, { - // Angular specific configuration defaults and overrides to ensure a functioning compilation. - suppressOutputPathCheck: true, - outDir: undefined, - sourceMap: false, - declaration: false, - declarationMap: false, - allowEmptyCodegenFiles: false, - annotationsAs: 'decorators', - enableResourceInlining: false, - supportTestBed: false, - supportJitMode: false, - // Disable removing of comments as TS is quite aggressive with these and can - // remove important annotations, such as /* @__PURE__ */ and comments like /* vite-ignore */. - removeComments: false, - }), - ); - } - abstract initialize( tsconfig: string, hostOptions: AngularHostOptions, diff --git a/packages/angular/build/src/tools/angular/compilation/angular-compilation_spec.ts b/packages/angular/build/src/tools/angular/compilation/angular-compilation_spec.ts index 5e520fbadef8..a867f666c349 100644 --- a/packages/angular/build/src/tools/angular/compilation/angular-compilation_spec.ts +++ b/packages/angular/build/src/tools/angular/compilation/angular-compilation_spec.ts @@ -128,6 +128,12 @@ describe('AngularCompilation', () => { await compilation.update?.(new Set(['/src/test.ts'])); expect(compilation.getCachedSourceFiles().has('/src/test.ts')).toBeFalse(); }); + + it('dynamically loads the @angular/compiler-cli module', async () => { + const compilerCli = await TypeScriptCompilation.loadCompilerCli(); + expect(compilerCli).toBeDefined(); + expect(typeof compilerCli.readConfiguration).toBe('function'); + }); }); describe('createAngularCompilation', () => { diff --git a/packages/angular/build/src/tools/angular/compilation/aot-compilation.ts b/packages/angular/build/src/tools/angular/compilation/aot-compilation.ts index ec68415e62fb..9fd160774cf7 100644 --- a/packages/angular/build/src/tools/angular/compilation/aot-compilation.ts +++ b/packages/angular/build/src/tools/angular/compilation/aot-compilation.ts @@ -22,10 +22,9 @@ import { replaceBootstrap } from '../transformers/jit-bootstrap-transformer'; import { lazyRoutesTransformer } from '../transformers/lazy-routes-transformer'; import { createWorkerTransformer } from '../transformers/web-worker-transformer'; import { - AngularCompilation, - AngularCompilationResult, + type AngularCompilationResult, DiagnosticModes, - EmitFileResult, + type EmitFileResult, } from './angular-compilation'; import { CompilerOptionOverrides, transformCompilerOptions } from './compiler-options'; import { collectHmrCandidates } from './hmr-candidates'; @@ -69,7 +68,7 @@ export class AotCompilation extends TypeScriptCompilation { compilerOptionOverrides?: CompilerOptionOverrides, ): Promise { // Dynamically load the Angular compiler CLI package - const { NgtscProgram, OptimizeFor } = await AngularCompilation.loadCompilerCli(); + const { NgtscProgram, OptimizeFor } = await TypeScriptCompilation.loadCompilerCli(); // Load the compiler configuration and transform as needed const { diff --git a/packages/angular/build/src/tools/angular/compilation/jit-compilation.ts b/packages/angular/build/src/tools/angular/compilation/jit-compilation.ts index b54f66701c6c..fee636219be0 100644 --- a/packages/angular/build/src/tools/angular/compilation/jit-compilation.ts +++ b/packages/angular/build/src/tools/angular/compilation/jit-compilation.ts @@ -16,10 +16,9 @@ import { createJitResourceTransformer } from '../transformers/jit-resource-trans import { lazyRoutesTransformer } from '../transformers/lazy-routes-transformer'; import { createWorkerTransformer } from '../transformers/web-worker-transformer'; import { - AngularCompilation, - AngularCompilationResult, + type AngularCompilationResult, DiagnosticModes, - EmitFileResult, + type EmitFileResult, } from './angular-compilation'; import { CompilerOptionOverrides, transformCompilerOptions } from './compiler-options'; import { TypeScriptCompilation } from './typescript-compilation'; diff --git a/packages/angular/build/src/tools/angular/compilation/typescript-compilation.ts b/packages/angular/build/src/tools/angular/compilation/typescript-compilation.ts index 7591e2028c36..970041f916fc 100644 --- a/packages/angular/build/src/tools/angular/compilation/typescript-compilation.ts +++ b/packages/angular/build/src/tools/angular/compilation/typescript-compilation.ts @@ -6,14 +6,46 @@ * found in the LICENSE file at https://angular.dev/license */ +import type * as ng from '@angular/compiler-cli'; import type { PartialMessage } from 'esbuild'; import ts from 'typescript'; import { toPosixPath } from '../../../utils/path'; -import { profileAsync } from '../../esbuild/profiling'; +import { profileAsync, profileSync } from '../../esbuild/profiling'; import { AngularCompilation, DiagnosticModes } from './angular-compilation'; import { convertTypeScriptDiagnostic } from './diagnostics'; export abstract class TypeScriptCompilation extends AngularCompilation { + static #angularCompilerCliModule?: typeof ng; + + static async loadCompilerCli(): Promise { + TypeScriptCompilation.#angularCompilerCliModule ??= await import('@angular/compiler-cli'); + + return TypeScriptCompilation.#angularCompilerCliModule; + } + + protected async loadConfiguration(tsconfig: string): Promise { + const { readConfiguration } = await TypeScriptCompilation.loadCompilerCli(); + + return profileSync('NG_READ_CONFIG', () => + readConfiguration(tsconfig, { + // Angular specific configuration defaults and overrides to ensure a functioning compilation. + suppressOutputPathCheck: true, + outDir: undefined, + sourceMap: false, + declaration: false, + declarationMap: false, + allowEmptyCodegenFiles: false, + annotationsAs: 'decorators', + enableResourceInlining: false, + supportTestBed: false, + supportJitMode: false, + // Disable removing of comments as TS is quite aggressive with these and can + // remove important annotations, such as /* @__PURE__ */ and comments like /* vite-ignore */. + removeComments: false, + }), + ); + } + protected readonly sourceFiles = new Map(); protected invalidateFiles(files: Iterable): void {