Skip to content

perf(svelte2tsx): use a module resolution cache in emitDts - #3093

Merged
jasonlyu123 merged 1 commit into
sveltejs:masterfrom
sam-easygo:emit-dts-module-resolution-cache
Aug 20, 2026
Merged

jasonlyu123 merged 1 commit into
sveltejs:masterfrom
sam-easygo:emit-dts-module-resolution-cache

Conversation

@sam-easygo

@sam-easygo sam-easygo commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

perf(svelte2tsx): use a module resolution cache in emitDts

Fixes #3094.

Summary

emitDts resolves every import through its compiler host with bare ts.resolveModuleName calls, without a ts.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 ModuleResolutionCache per resolution host in createTsCompilerHost and passes it to the two existing ts.resolveModuleName calls. Each of the two hosts (plain ts.sys, and the svelte-aware system) gets its own cache because they disagree about whether virtual .svelte.ts/.svelte.js paths exist, so their results must not be mixed.

This brings emitDts in line with the rest of the repo: the language server already maintains a deliberate module resolution cache in its module-loader.ts (see #2754, #2902); emitDts was 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 the emitDts/svelte-package build 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 each svelte-package run inside emitDts, and ~52% of total build CPU in uncached module resolution.

With this change applied via a pnpm patch (identical diff):

Cold build of the 29 packages Before After
Sum of per-package build times 173.0s 113.2s
Process CPU (user+sys) 133s 99s
Wall time (14 cores) 21.0s 13.3s

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

  • Within one emitDts call file contents do not change, so caching resolutions is sound.
  • The svelteMap population is unaffected: the first resolution of each (directory, specifier) pair still goes through svelteSys.fileExists, which registers .svelte files; cache hits only replay results whose first resolution already did that work.
  • Output verified byte-for-byte identical: recursive diff of every emitted dist/ tree (d.ts + d.ts.map) across all 29 packages, patched vs unpatched, from both clean and warm starting states.

Test plan

  • pnpm test in packages/svelte2tsx: 370 passing, including the emitDts suite (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.
  • Changeset included (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.

@changeset-bot

changeset-bot Bot commented Aug 5, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 3132ac6

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
svelte2tsx Patch

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

Comment thread packages/svelte2tsx/src/emitDts.ts Outdated
@sam-easygo
sam-easygo force-pushed the emit-dts-module-resolution-cache branch 4 times, most recently from 1fbc49b to 9fba132 Compare August 12, 2026 04:20
@sam-easygo
sam-easygo force-pushed the emit-dts-module-resolution-cache branch from 9fba132 to f8e36b6 Compare August 13, 2026 10:58
@sam-easygo
sam-easygo requested a review from jasonlyu123 August 13, 2026 10:58
@jasonlyu123

Copy link
Copy Markdown
Member

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?

@sam-easygo
sam-easygo force-pushed the emit-dts-module-resolution-cache branch from 188cd02 to 1e4da9a Compare August 18, 2026 06:16
@sam-easygo

Copy link
Copy Markdown
Contributor Author

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?

@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

@jasonlyu123

Copy link
Copy Markdown
Member

Oh, it's from your commit message. Can you clean that up?

@sam-easygo
sam-easygo force-pushed the emit-dts-module-resolution-cache branch from 1e4da9a to 3132ac6 Compare August 18, 2026 22:46
@sam-easygo

Copy link
Copy Markdown
Contributor Author

Oh, it's from your commit message. Can you clean that up?

@jasonlyu123 Oh sorry about that not even sure how that happened, cleaned up now

@jasonlyu123
jasonlyu123 merged commit 092af38 into sveltejs:master Aug 20, 2026
3 checks passed
@github-actions github-actions Bot mentioned this pull request Aug 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

emitDts resolves modules without a ModuleResolutionCache, dominating svelte-package build time

2 participants