Skip to content

perf: build a solution on the programs of the build before it - #342

Merged
alexander-akait merged 1 commit into
mainfrom
perf/reuse-the-built-solution
Sep 14, 2026
Merged

alexander-akait merged 1 commit into
mainfrom
perf/reuse-the-built-solution

Conversation

@alexander-akait

@alexander-akait alexander-akait commented Sep 14, 2026

Copy link
Copy Markdown
Member

Summary

A rebuild in build mode made every project's program from nothing. tsc -b reads what it can back from .tsbuildinfo, but the sources are parsed and the project checked over again — so the one thing the non-build path already does, keeping its program between rebuilds (#331), the solution path did not.

The solution builder's host takes a createProgram of its own, which is the only hook it exposes. Ours keeps the parsed source files and hands each project the program the last build left it.

Measured, and the alternative was measured too. Over a generated two-project, 302-file solution, one file edited between passes, medians of 10 rebuilds over three interleaved runs:

first build rebuild RSS
today 1243 ms 468 ms 412 MB
this 1239 ms 149 ms 267 MB

createSolutionBuilderWithWatch — the obvious candidate, and what fork-ts-checker-webpack-plugin uses — was tried first and rejected on the numbers: with its watchers replaced by ours (webpack owns the watching here, per #334) its rebuilds were no faster than today's ~500 ms, it held 503 MB, and after the second pass invalidateProject stopped rebuilding at all, so it answered from stale programs. It only works with TypeScript's own file watchers, which would duplicate webpack's.

One thing measuring turned up that this PR does not fix. build mode inherits tsc -b's timestamp up-to-date check, so an edit whose mtime does not exceed the previous build's outputs — an edit made while a build is running — is silently skipped and reported as clean until something else changes. It reproduces on main (status=UpToDate, input mtime equal to .tsbuildinfo's) and is unrelated to this change; worth its own issue.

What kind of change does this PR introduce?

perf

Did you add tests for your changes?

Yes — test/typescript/references.test.js watches a solution over an edit and asserts each project of the second build is handed the very same program object the first returned. tsc -b reads an old program back from .tsbuildinfo either way, so the recorder mock had to record object identity rather than "was there an old program": with that, reverting the change fails the test.

Does this PR introduce a breaking change?

No — same diagnostics, same options.

If relevant, what needs to be documented once your changes are merged or what have you already documented?

n/a — no option changed.

Use of AI

Claude Code wrote the benchmark, measured the three candidate designs, wrote the change, the test and this description; I reviewed all of it.

Rebased onto main now that #341 has landed, so this is one commit. #343 sits on top of it.

🤖 Generated with Claude Code

https://claude.ai/code/session_01GzZci4NQeiqwdrVfd7dGXy

A rebuild in `build` mode made every project's program from nothing:
`tsc -b` reads what it can back from `.tsbuildinfo`, but the sources are
parsed and the project checked over again. The builder is handed a
`createProgram` of ours now, which keeps the parsed files and hands each
project the program the last build left it.

Over a two-project, 302-file solution, a rebuild after one edit falls
from 468 ms to 149 ms (medians of 10, three runs) and holds 267 MB
rather than 412 MB; a first build is unchanged at ~1240 ms.
@alexander-akait
alexander-akait force-pushed the perf/reuse-the-built-solution branch from 8867de9 to 86e0f2c Compare September 14, 2026 04:51
@alexander-akait
alexander-akait merged commit f80fcee into main Sep 14, 2026
13 checks passed
@alexander-akait
alexander-akait deleted the perf/reuse-the-built-solution branch September 14, 2026 05:10
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.

1 participant