Skip to content

perf(engine): typecheck a save over the project's own files only - #191

Merged
Upd4ting merged 2 commits into
mainfrom
perf/typecheck-own-files
Nov 10, 2026
Merged

Upd4ting merged 2 commits into
mainfrom
perf/typecheck-own-files

Conversation

@Upd4ting

@Upd4ting Upd4ting commented Nov 10, 2026 •

Copy link
Copy Markdown
Member

Summary

Every builder save typechecks the project before it writes. The check asked TypeScript for the whole program's diagnostics. Those include every declaration file in node_modules, and the builder drops their errors anyway. On the DMS module template (declaration: true, no skipLibCheck) that dropped work was most of each save.

 relevantDiagnostics(project)            engine/writable.ts
-  project.getPreEmitDiagnostics()       whole program, node_modules .d.ts included
+  for each program file not in node_modules
+    sourceFile.getPreEmitDiagnostics()  that file only
   drop file-less and node_modules diagnostics

The loop walks the program's files, not project.getSourceFiles(), so a file that only an import reaches is still checked. Examples are a file created in an editor while the server runs, or one outside include.

Evidence

Evidence level: benchmark of the engine operations, plus an end-to-end profile in the dashboard.

Workload: the repository playground (Board page, orders table) copied into a fixture inside the package. Each operation is called the way the dashboard calls it, with the draft built the way structureToDraft builds it. Sides run interleaved, 5 runs each of 3 calls, on a shared and noisy server.

Operation main this PR
SetPageBlocks (a dashboard save) 1419 ms (1329–1931) 437 ms (369–499)
ConfigurePage 1044 ms (994–1253) 107 ms (100–119)
AddBlock 1566 ms (1430–1663) 621 ms (581–643)
SetPageBlocks, 10 pages 2348 ms (2322–3550) 824 ms (761–1177)

The typecheck alone, measured with the template's tsconfig: 4568 ms (3672–5216) before, 496 ms (390–632) after. The diagnostics are the same with and without a type error, including an error in a file outside include and one in a file created after the project was parsed. With skipLibCheck: true there is no change: 272 ms before, 248 ms after.

Cumulative impact: about 1 s less waiting on each save in the editor, every save. The order of diagnostics across files can change. Only the joined error banner reads that order.

The engine specs (test:unit) pass: 523 passing.

Verification

  • pnpm run checks passes. Main fails sync:check on a stale compat row in packages/dms-builder/README.md (interface-dms-builder 0.4.0, published 0.4.1), so a separate commit syncs it. It is the same line build(deps): move to @antelopejs/tooling-configs 0.5.0 #190 carries, byte for byte, so whichever of the two lands second has an empty or trivial conflict there.
  • Verify harness on a stack of the three perf PRs: smoke, blocks (3), pages (3) and resources (4) journeys pass. Dashboard save, Save click to the server's answer, 15 saves per side: 2325 ms (2010–3792) on main, 630 ms (440–1102) with the three PRs.
  • formal-page-save: the same output on main and on this branch. The only finding is the recorded F2 (Moving a page with an unsaved draft lets the next Save overwrite an outside change without the stale banner #163), which none of these lines touch. The gate flags the covered code's emit as changed.

Merge Danger

Door: two-way. Nothing is stored. A revert restores the old check.

Blast Radius: saves.

A diagnostic located in an own file that TypeScript reports only while checking a node_modules declaration file would no longer refuse a save. Neither review found a checker path that does this.

@Upd4ting
Upd4ting merged commit c16bfa5 into main Nov 10, 2026
13 checks passed
@Upd4ting
Upd4ting deleted the perf/typecheck-own-files branch November 10, 2026 16:24
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