Skip to content

Commit 4bf93b6

Browse files
committed
perf(bridge): share stable declaration SFs process-globally (issue #6)
The stable host SourceFile cache (bound host ASTs for bundled libs and node_modules .d.ts) was keyed per LS host, so every configured project materialized its own full copy of the entire declaration closure. In a 3-tsconfig probe the same ~130-file closure was fully materialized once per project (509 full SFs), and every additional tsconfig re-paid it — the dominant tsserver memory cost in multi-project workspaces and the reason thousand-.vue repos were untenable. The cache is now process-global: stable .d.ts binds identically for a given content version and ensureHostSourceFileBound brands after a single bind (no re-binding), so one entry serves every project, with replacement on scriptVersion change. Measured (8 .vue opens, 3 tsconfigs): full materializations 509 -> 139, V8 heap 419 -> 183 MB (-56%), putting the multi-project cost on par with single-project. Gates: sourcefile-guard, sim-edit 200, sim-xfile 71/71, qi-emptyparity 12/12, display-tokens 6/6, computed-literal 7/7, check:lib/enums/bundle-shape, volar 205 passed, sim-nav 37,409 units CONSERVED (new=0).
1 parent 3749fa4 commit 4bf93b6

1 file changed

Lines changed: 9 additions & 1 deletion

File tree

‎patches/typescript/overlay/src/compiler/tsgoChecker.ts‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,14 @@ const _programShapeNoHost = new Map<string, TnbProgramShape>();
443443
// share across generations. Keyed per LS host so closed projects drop entries.
444444
const _hostSfStableByHost = new WeakMap<object, Map<string, { version: string; sf: any }>>();
445445
const _hostSfStableNoHost = new Map<string, { version: string; sf: any }>();
446+
// Process-global stable SF cache: stable .d.ts (bundled lib + node_modules)
447+
// binds identically for a given content version, and ensureHostSourceFileBound
448+
// brands after one bind (no re-bind), so ONE entry serves every project in the
449+
// process. The per-lsHost cache above duplicated the entire lib closure per
450+
// project — the dominant tsserver memory cost in multi-tsconfig workspaces
451+
// (issue #6, ~54MB/.vue per open). Entries are replaced on scriptVersion
452+
// change; the set is bounded by the on-disk declaration set.
453+
const _hostSfStableGlobal = new Map<string, { version: string; sf: any }>();
446454
function isStableHostSfPath(p: string): boolean {
447455
if (process.env.TNB_DISABLE_STABLE_HOST_SF === "1") return false;
448456
return p.endsWith(".d.ts") && (p.includes("/node_modules/") || isHostLibFile(p));
@@ -4144,7 +4152,7 @@ export function createTsgoProgram(
41444152
if (sfCache.has(cacheKey)) return sfCache.get(cacheKey);
41454153
// Disk-stable library declarations: reuse the bound host AST from the
41464154
// previous program generation when the script version is unchanged.
4147-
const stableSfCache = isStableHostSfPath(hostFileName) ? getHostSfStableCache(hostForLs()) : undefined;
4155+
const stableSfCache = isStableHostSfPath(hostFileName) ? _hostSfStableGlobal : undefined;
41484156
if (stableSfCache) {
41494157
const hit = stableSfCache.get(hostFileName);
41504158
if (hit && hit.version === String(scriptVersion)) {

0 commit comments

Comments
 (0)