perf(svelte2tsx): use a module resolution cache in emitDts - #3093
Conversation
🦋 Changeset detectedLatest commit: 3132ac6 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
1fbc49b to
9fba132
Compare
9fba132 to
f8e36b6
Compare
|
Weird. The head of the branch seems a bit strange after I updated the branch. Now "Squash and merge" preview show commits in the main branch as changes in this PR. Can you try to rebase it again? |
188cd02 to
1e4da9a
Compare
@jasonlyu123 strange, no longer had the button to update the branch just on the github UI but rebased locally on latest and force pushed but will need the workflow approval again |
|
Oh, it's from your commit message. Can you clean that up? |
1e4da9a to
3132ac6
Compare
@jasonlyu123 Oh sorry about that not even sure how that happened, cleaned up now |
perf(svelte2tsx): use a module resolution cache in emitDts
Fixes #3094.
Summary
emitDtsresolves every import through its compiler host with barets.resolveModuleNamecalls, without ats.createModuleResolutionCache. Nothing is cached across the program's files, so each of the (typically hundreds of) node_modules declaration files re-runs the full node_modules resolution walk (open/stat/realpath syscalls) for every import statement.This PR creates a
ModuleResolutionCacheper resolution host increateTsCompilerHostand passes it to the two existingts.resolveModuleNamecalls. Each of the two hosts (plaints.sys, and the svelte-aware system) gets its own cache because they disagree about whether virtual.svelte.ts/.svelte.jspaths exist, so their results must not be mixed.This brings
emitDtsin line with the rest of the repo: the language server already maintains a deliberate module resolution cache in itsmodule-loader.ts(see #2754, #2902);emitDtswas the remaining resolution path without one. It is also complementary to #2963, which caches script-AST parsing on the language-server path; this PR addresses module resolution on theemitDts/svelte-packagebuild path.Benchmarks
Profiled in a pnpm + Turborepo design-system monorepo with 29 Svelte 5 component packages, each built with
svelte-package(TypeScript 6.0.3, svelte2tsx 0.7.57, ~880 node_modules declaration files per program, macOS/arm64). V8 profiles showed ~82% of eachsvelte-packagerun insideemitDts, and ~52% of total build CPU in uncached module resolution.With this change applied via a pnpm patch (identical diff):
A representative single package dropped from ~10.9s to ~6.7s under parallel load, and to ~2s when built alone. The monorepo has been running this exact diff in CI since.
Correctness
emitDtscall file contents do not change, so caching resolutions is sound.(directory, specifier)pair still goes throughsvelteSys.fileExists, which registers.sveltefiles; cache hits only replay results whose first resolution already did that work.dist/tree (d.ts + d.ts.map) across all 29 packages, patched vs unpatched, from both clean and warm starting states.Test plan
pnpm testinpackages/svelte2tsx: 370 passing, including theemitDtssuite (no new tests: the change is a pure caching pass-through with no observable behaviour, and byte-identical output is verified above).pnpm lint(prettier check): clean.pnpm format: no changes needed.svelte2tsx: patch).A note on authorship
I use AI tooling in my workflow and it helped discover and author this change. If AI-assisted contributions are against the maintainers' stance, I am entirely happy for this to be closed.