Skip to content

build: Parallelize Hey API and declaration emit, make edit linear - #132

Merged
BYK merged 2 commits into
mainfrom
perf/build-parallel
Nov 5, 2026
Merged

BYK merged 2 commits into
mainfrom
perf/build-parallel

Conversation

@sentry-junior

@sentry-junior sentry-junior Bot commented Nov 5, 2026

Copy link
Copy Markdown
Contributor

Follow-up to your approval comment on #131 ("see if we can benefit from any parallelization or optimizations in Hey API code"). This cuts pnpm build from about 48 s to about 25 s in my sandbox (4 vCPUs).

Where the time went (on main)

Phase Before After
Hey API createClient 5.4 s 4.0 s
Build steps in scripts/ 14.6 s 1.5 s
esbuild bundles + tsc --emitDeclarationOnly 30.4 s 17.4 s

What changes

  • edit is linear: describe-valibot-schemas spent 13 s of the 14.6 s step phase in lib/generated-source.mjs's edit. It sliced the whole 2.6 MB valibot.gen.ts once per edit, about 6,500 times. edit now builds the result in one pass.
    • It keeps the old order for insertions at the same position.
    • It now throws on overlapping edits, which the doc comment already ruled out.
    • New test/generated-source.test.ts covers both.
  • Declarations in parallel: tsc --emitDeclarationOnly spent 25 of its 30 s checking, mostly on the Valibot and Zod schemas. Neither of those files imports anything else from src/.
    • New lib/emit-declarations.mjs reads tsconfig.json and builds three programs in worker threads: Valibot, Zod, and everything else.
    • Each worker reports its diagnostics and writes its declarations, and a type error still fails the build. I checked that with a file that has a deliberate error.
    • The workers run alongside the esbuild bundles. Valibot is now the slowest step, at about 15 s.
  • Hey API in parallel: the Valibot and Zod plugins read nothing the TypeScript and SDK plugins write. New lib/hey-api.mjs runs the three plugin groups in worker threads.
    • Each group produces byte-identical files to the combined run; I compared them file by file.
    • Hey API empties its output directory first, so the validator groups write to a temp directory and their files are copied into src/.
    • The Hey API config (describeNullableValues, validatorOptions) moves from build.mjs into this module.

Output

  • src/ is byte-identical to main's.
  • In dist/, only valibot.gen.d.ts and zod.gen.d.ts change, and only in the order of union members and enum keys. For example, "GET" | "HEAD" | "OPTIONS" | … becomes "GET" | "POST" | "HEAD" | …. TypeScript orders unions by when it first created each literal type, and that depends on what else is in the program. The types themselves don't change. Every other .d.ts file is byte-identical.

Cost

Peak memory of the build process goes from about 1.4 GB (plus the separate tsc process, about 1.6 GB) to about 2.3 GB in one process.

Verification

  • pnpm build passes.
  • pnpm typecheck passes, and so do all 635 tests in pnpm test.
  • With diff -r against main's build, src/ is byte-identical. In dist/, only the two files above differ.

--

View Session in Sentry

The build took about 48 s. Most of it went to three places:

- describe-valibot-schemas spent 13 s in `edit`, which rebuilt the
  2.6 MB valibot.gen.ts once per edit, about 6,500 times. `edit` now
  builds the result in one pass.
- `tsc --emitDeclarationOnly` took 30 s, mostly checking the Valibot and
  Zod schemas, which import nothing else from src/. lib/emit-declarations.mjs
  emits from tsconfig.json in three worker threads: Valibot, Zod, and the
  rest. They run alongside the esbuild bundles.
- Hey API took 5.4 s. The validator plugins read nothing the TypeScript
  and SDK plugins write, so lib/hey-api.mjs runs the three plugin groups
  in worker threads; each produces the same files as the combined run.

src/ is byte-identical to main's. In dist/, only valibot.gen.d.ts and
zod.gen.d.ts change, and only in the order of union members and enum
keys: TypeScript orders them by when it first created each literal type,
which depends on what else is in the program.

Co-Authored-By: BYK <burak.kaya@sentry.io>

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 9183811. Configure here.

Comment thread lib/emit-declarations.mjs Resolved
tsc reports file names with forward slashes on Windows, so the grouped
Valibot and Zod files also landed in the rest program and were emitted
twice. Compare resolved paths, and fail when a group names a file that
tsconfig.json does not include.
@BYK
BYK merged commit c843061 into main Nov 5, 2026
11 checks passed
@BYK
BYK deleted the perf/build-parallel branch November 5, 2026 13:40
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