Skip to content

runTsc: tsc -b --watch iterations rebuild the whole Program — full re-parse + re-resolve on every file change (no oldProgram reuse) #314

Description

@NullVoxPopuli

Note

This issue was investigated and written by an AI (Claude), supervised by @NullVoxPopuli. Apologies in advance for any incorrectness — the measurements are real, but the mechanism analysis is a hypothesis and clearly labeled as such.

Summary

Under runTsc in solution-builder watch mode (tsc -b --watch), every watch iteration reconstructs the changed project's Program from scratch: all source files re-parse and the entire module graph re-resolves, even for a one-line change. Plain --watch (createWatchProgram path) through the same proxy reuses the old program correctly.

Measurements

One-line edit in a 19,286-file project (glint's ember-tsc, @volar/typescript 2.4.28, TS 6.0.3, 59-project composite monorepo), --extendedDiagnostics:

phase -b --watch iteration plain --watch iteration
Parse 7.29s 0.00s
ResolveModule 7.22s 0.03s
Program 27.57s 1.80s
Check 0.14s 0.15s
Total 29.98s 2.14s

The -b --watch iteration costs the same as that project's initial cold build (29.03s) — only diagnostics scoping (buildinfo layer) survives; in-memory SourceFile/resolution reuse does not.

Suspected mechanism (unproven)

Two candidates in proxyCreateProgram:

  1. options.host = { ...originalHost } with a fresh getSourceFile closure on every createProgram call — the solution builder's per-project rebuilds may lose SourceFile reuse through the re-wrapped host.
  2. When a plugin sets resolveHiddenExtensions (glint does), every module literal resolves through the proxy's wrapper, bypassing TS's reused-resolution fast path (structureIsReused).

Happy to run further instrumentation (--cpu-prof, checking whether oldProgram survives through the proxy) if useful.

Context

🤖 Generated with Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions