Skip to content

Commit 14451e2

Browse files
clydinalan-agius4
authored andcommittedDec 5, 2024·
perf(@angular/build): reuse TS package.json cache when rebuilding
TypeScript 5.6 and higher added functionality that will search for a `package.json` file for source files that are part of the program (e.g., `.d.ts`) and within a node modules directory. This can be an expensive tasks especially considering the large amount of `.d.ts` files within packages. TypeScript supports using a cache of known `package.json` files to improve the performance of this task. The Angular CLI will now provide and reuse this cache across rebuilds during watch mode. This includes the use of `ng serve`. The performance difference is most apparent for the Angular template diagnostic step of the build. Internally the Angular compiler creates a new template typechecking program which causes the `package.json` search process to occur. By leveraging the cache, this process becomes a series of cache hits. In the event that files are modified within the node modules directory, the cache is invalidated and the following rebuild may be longer as a result. (cherry picked from commit 75998eb)
1 parent 23667ed commit 14451e2

File tree

3 files changed

+34
-16
lines changed

3 files changed

+34
-16
lines changed
 

‎packages/angular/build/src/tools/angular/angular-host.ts

+10-8
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ export function createAngularCompilerHost(
164164
typescript: typeof ts,
165165
compilerOptions: AngularCompilerOptions,
166166
hostOptions: AngularHostOptions,
167+
packageJsonCache: ts.PackageJsonInfoCache | undefined,
167168
): AngularCompilerHost {
168169
// Create TypeScript compiler host
169170
const host: AngularCompilerHost = typescript.createIncrementalCompilerHost(compilerOptions);
@@ -229,16 +230,17 @@ export function createAngularCompilerHost(
229230
return hostOptions.modifiedFiles;
230231
};
231232

233+
// Provide a resolution cache to ensure package.json lookups are cached
234+
const resolutionCache = typescript.createModuleResolutionCache(
235+
host.getCurrentDirectory(),
236+
host.getCanonicalFileName.bind(host),
237+
compilerOptions,
238+
packageJsonCache,
239+
);
240+
host.getModuleResolutionCache = () => resolutionCache;
241+
232242
// Augment TypeScript Host for file replacements option
233243
if (hostOptions.fileReplacements) {
234-
// Provide a resolution cache since overriding resolution prevents automatic creation
235-
const resolutionCache = typescript.createModuleResolutionCache(
236-
host.getCurrentDirectory(),
237-
host.getCanonicalFileName.bind(host),
238-
compilerOptions,
239-
);
240-
host.getModuleResolutionCache = () => resolutionCache;
241-
242244
augmentHostWithReplacements(typescript, host, hostOptions.fileReplacements, resolutionCache);
243245
}
244246

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

+23-7
Original file line numberDiff line numberDiff line change
@@ -66,20 +66,36 @@ export class AotCompilation extends AngularCompilation {
6666
hostOptions.externalStylesheets ??= new Map();
6767
}
6868

69-
// Collect stale source files for HMR analysis of inline component resources
69+
// Reuse the package.json cache from the previous compilation
70+
const packageJsonCache = this.#state?.compilerHost
71+
.getModuleResolutionCache?.()
72+
?.getPackageJsonInfoCache();
73+
74+
const useHmr = compilerOptions['_enableHmr'];
75+
7076
let staleSourceFiles;
71-
if (compilerOptions['_enableHmr'] && hostOptions.modifiedFiles && this.#state) {
77+
let clearPackageJsonCache = false;
78+
if (hostOptions.modifiedFiles && this.#state) {
7279
for (const modifiedFile of hostOptions.modifiedFiles) {
73-
const sourceFile = this.#state.typeScriptProgram.getSourceFile(modifiedFile);
74-
if (sourceFile) {
75-
staleSourceFiles ??= new Map<string, ts.SourceFile>();
76-
staleSourceFiles.set(modifiedFile, sourceFile);
80+
// Clear package.json cache if a node modules file was modified
81+
if (!clearPackageJsonCache && modifiedFile.includes('node_modules')) {
82+
clearPackageJsonCache = true;
83+
packageJsonCache?.clear();
84+
}
85+
86+
// Collect stale source files for HMR analysis of inline component resources
87+
if (useHmr) {
88+
const sourceFile = this.#state.typeScriptProgram.getSourceFile(modifiedFile);
89+
if (sourceFile) {
90+
staleSourceFiles ??= new Map<string, ts.SourceFile>();
91+
staleSourceFiles.set(modifiedFile, sourceFile);
92+
}
7793
}
7894
}
7995
}
8096

8197
// Create Angular compiler host
82-
const host = createAngularCompilerHost(ts, compilerOptions, hostOptions);
98+
const host = createAngularCompilerHost(ts, compilerOptions, hostOptions, packageJsonCache);
8399

84100
// Create the Angular specific program that contains the Angular compiler
85101
const angularProgram = profileSync(

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ export class JitCompilation extends AngularCompilation {
5353
compilerOptionsTransformer?.(originalCompilerOptions) ?? originalCompilerOptions;
5454

5555
// Create Angular compiler host
56-
const host = createAngularCompilerHost(ts, compilerOptions, hostOptions);
56+
const host = createAngularCompilerHost(ts, compilerOptions, hostOptions, undefined);
5757

5858
// Create the TypeScript Program
5959
const typeScriptProgram = profileSync('TS_CREATE_PROGRAM', () =>

0 commit comments

Comments
 (0)
Please sign in to comment.