Skip to content

Commit 954fa55

Browse files
authored
Merge pull request #202 from arethetypeswrong/cache-programs
Cache programs
2 parents a4d3f21 + 33abbdb commit 954fa55

File tree

3 files changed

+28
-10
lines changed

3 files changed

+28
-10
lines changed

packages/core/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
"@andrewbranch/untar.js": "^1.0.3",
5454
"cjs-module-lexer": "^1.2.3",
5555
"fflate": "^0.8.2",
56+
"lru-cache": "^11.0.1",
5657
"semver": "^7.5.4",
5758
"typescript": "5.6.1-rc",
5859
"validate-npm-package-name": "^5.0.0"

packages/core/src/internal/multiCompilerHost.ts

+18-10
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import ts from "typescript";
2+
import { LRUCache } from "lru-cache";
23
import type { ModuleKind } from "../types.js";
34
import type { Package } from "../createPackage.js";
45

@@ -37,6 +38,7 @@ const getCanonicalFileName = ts.createGetCanonicalFileName(false);
3738
const toPath = (fileName: string) => ts.toPath(fileName, "/", getCanonicalFileName);
3839

3940
export class CompilerHostWrapper {
41+
private programCache = new LRUCache<string, ts.Program>({ max: 2 });
4042
private compilerHost: ts.CompilerHost;
4143
private compilerOptions: ts.CompilerOptions;
4244
private normalModuleResolutionCache: ts.ModuleResolutionCache;
@@ -162,12 +164,17 @@ export class CompilerHostWrapper {
162164
return `${resolutionMode ?? 1}:${+!!noDtsResolution}:${+!!allowJs}:${moduleSpecifier}`;
163165
}
164166

167+
private getProgram(rootNames: readonly string[], options: ts.CompilerOptions) {
168+
const key = programKey(rootNames, options);
169+
let program = this.programCache.get(key);
170+
if (!program) {
171+
this.programCache.set(key, (program = ts.createProgram({ rootNames, options, host: this.compilerHost })));
172+
}
173+
return program;
174+
}
175+
165176
createPrimaryProgram(rootName: string) {
166-
const program = ts.createProgram({
167-
rootNames: [rootName],
168-
options: this.compilerOptions,
169-
host: this.compilerHost,
170-
});
177+
const program = this.getProgram([rootName], this.compilerOptions);
171178

172179
program.resolvedModules?.forEach((cache, path) => {
173180
let ownCache = this.resolvedModules.get(path);
@@ -199,11 +206,8 @@ export class CompilerHostWrapper {
199206
) {
200207
throw new Error("Cannot override resolution-affecting options for host due to potential cache polution");
201208
}
202-
return ts.createProgram({
203-
rootNames,
204-
options: extraOptions ? { ...this.compilerOptions, ...extraOptions } : this.compilerOptions,
205-
host: this.compilerHost,
206-
});
209+
const options = extraOptions ? { ...this.compilerOptions, ...extraOptions } : this.compilerOptions;
210+
return this.getProgram(rootNames, options);
207211
}
208212

209213
getResolvedModule(sourceFile: ts.SourceFile, moduleName: string, resolutionMode: ts.ResolutionMode) {
@@ -304,3 +308,7 @@ class TraceCollector {
304308
this.traces.length = 0;
305309
}
306310
}
311+
312+
function programKey(rootNames: readonly string[], options: ts.CompilerOptions) {
313+
return JSON.stringify([rootNames, Object.entries(options).sort(([k1], [k2]) => k1.localeCompare(k2))]);
314+
}

pnpm-lock.yaml

+9
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)