Skip to content

Commit 5e55682

Browse files
committed
perf(@angular/build): cache transformed configuration in TypeScript compilation
When `rootFiles` are explicitly provided (such as in library builds), avoid re-reading and re-parsing `tsconfig.json` and traversing the project directory structure on every watch rebuild. Cache the `TransformedConfiguration` and invalidate it only when a `.json` configuration file changes.
1 parent a0a6b42 commit 5e55682

1 file changed

Lines changed: 20 additions & 2 deletions

File tree

‎packages/angular/build/src/tools/angular/compilation/typescript-compilation.ts‎

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export interface TransformedConfiguration {
2424

2525
export abstract class TypeScriptCompilation extends AngularCompilation {
2626
static #angularCompilerCliModule?: typeof ng;
27+
#cachedConfiguration?: TransformedConfiguration;
2728

2829
static async loadCompilerCli(): Promise<typeof ng> {
2930
TypeScriptCompilation.#angularCompilerCliModule ??= await import('@angular/compiler-cli');
@@ -36,6 +37,12 @@ export abstract class TypeScriptCompilation extends AngularCompilation {
3637
compilerOptionOverrides?: CompilerOptionOverrides,
3738
buildType: 'application' | 'library' = 'application',
3839
): Promise<TransformedConfiguration> {
40+
// When `rootFiles` are explicitly provided (e.g., library builder), avoid re-parsing `tsconfig.json`
41+
// and walking the project directory tree via `readConfiguration` on every watch rebuild (~200-350ms on large libraries).
42+
if (compilerOptionOverrides?.rootFiles?.length && this.#cachedConfiguration) {
43+
return this.#cachedConfiguration;
44+
}
45+
3946
const { readConfiguration } = await TypeScriptCompilation.loadCompilerCli();
4047

4148
const {
@@ -82,19 +89,30 @@ export abstract class TypeScriptCompilation extends AngularCompilation {
8289
buildType,
8390
);
8491

85-
return {
92+
const config: TransformedConfiguration = {
8693
compilerOptions,
8794
rootNames,
8895
errors,
8996
warnings,
9097
};
98+
99+
if (compilerOptionOverrides?.rootFiles?.length) {
100+
this.#cachedConfiguration = config;
101+
}
102+
103+
return config;
91104
}
92105

93106
protected readonly sourceFiles = new Map<string, ts.SourceFile>();
94107

95108
protected invalidateFiles(files: Iterable<string>): void {
96109
for (const file of files) {
97-
this.sourceFiles.delete(toPosixPath(file));
110+
const posixFile = toPosixPath(file);
111+
this.sourceFiles.delete(posixFile);
112+
if (/\.json$/i.test(posixFile)) {
113+
// If a tsconfig changes, we need to re-read the configuration.
114+
this.#cachedConfiguration = undefined;
115+
}
98116
}
99117
}
100118

0 commit comments

Comments
 (0)