Skip to content

Commit 29d48fd

Browse files
committed
build(spec): drop the DTS pass's duplicate type check (noCheck)
The spec DTS pass sat at 92% of its 6144 MB heap ceiling (5658 MB live after mark-compact, 8 GB cgroup, 8cdbe0c), so CI runs near the margin ended in ERR_WORKER_OUT_OF_MEMORY. rollup-plugin-dts forces noEmitOnError, so the pass type-checked every file it emitted, in each of the one-per-entry programs tsup's bundled rollup-plugin-dts builds. That check duplicates the typecheck script over the same tsconfig. noCheck drops it: 5083 MB live, 134s instead of 181-194s. The emitted declarations are the same types. They differ from main only in union/property order, and main's own reruns differ that way too. The docblock now records the per-entry-program cause, today's measurements, and the fact that the pass is not byte-stable. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014EJ1ED8X4MMrT18BhVx4tx
1 parent 8cdbe0c commit 29d48fd

1 file changed

Lines changed: 49 additions & 15 deletions

File tree

‎packages/spec/tsup.config.ts‎

Lines changed: 49 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -176,26 +176,59 @@ const swapServerOnlyGrammarArm: Plugin = {
176176
* dependency — so this pass meets the container's limit ALONE, with no
177177
* parallelism to cap.
178178
*
179-
* Measured on this package's DTS pass, inside a cgroup capped at 8192 MB
180-
* (peak anonymous RSS of the whole process tree):
179+
* 6144 is the largest ceiling whose WORST case still fits: V8 cannot exceed
180+
* it, and the pass's non-heap overhead measures ~250 MB, so the bound is
181+
* ~6.4 GB inside an 8 GB container.
181182
*
182-
* ceiling result peak RSS wall
183-
* 12288 ok, but only ~0.9 GB spare 7290 MB 132s
184-
* 6144 ok 5794 MB 134s
185-
* 5120 ok 5328 MB 148s
186-
* 4096 ERR_WORKER_OUT_OF_MEMORY — 113s
183+
* WHY THE PASS IS THIS HEAVY: ONE `ts.Program` PER ENTRY. tsup 8.5.1 runs the
184+
* pass through its bundled rollup-plugin-dts 6.1.1, whose `createPrograms`
185+
* groups entries by a directory key. tsup always passes the tsconfig path, and
186+
* on that path every entry after the first is keyed by its OWN directory (the
187+
* same code is in rollup-plugin-dts 6.5.1). So each entry above gets its own
188+
* program, which parses, binds and emits its whole reachable graph again: the
189+
* peak grows with entries × graph, not with the graph. ⇒ Every entry added to
190+
* `entries` adds a program to this pass.
187191
*
188-
* 6144 is chosen as the largest ceiling whose WORST case still fits: V8 cannot
189-
* exceed it, and the pass's non-heap overhead measured ~250 MB, so the bound is
190-
* ~6.4 GB inside an 8 GB container. Every completing ceiling emitted a
191-
* byte-identical declaration tree (122 files, one sha256 over all of them), so
192-
* this number buys headroom and costs nothing but GC time.
192+
* `noCheck`: rollup-plugin-dts forces `noEmitOnError`, which made every one of
193+
* those programs also semantically CHECK each file it emitted — a type check
194+
* the `typecheck` script (`tsc --noEmit` over this same tsconfig, run by the
195+
* required `TypeScript Type Check` job) already performs once. `noCheck` drops
196+
* only that duplicate. Syntactic, option, global and declaration diagnostics
197+
* still fail the pass, so a declaration that cannot be emitted still stops the
198+
* build; a plain type error in `src/` is `typecheck`'s to report, not this
199+
* pass's.
200+
*
201+
* Measured on 8cdbe0c6e5's source, DTS pass alone at the 6144 ceiling, inside a
202+
* cgroup capped at 8192 MB. Live heap is the largest heap V8 kept after a
203+
* mark-compact (`--trace-gc`); peak RSS is the peak anonymous RSS of the whole
204+
* process tree:
205+
*
206+
* pass live heap peak RSS wall
207+
* duplicate check on (before) 5658 MB 6177 MB 181-194s
208+
* noCheck (this config) 5083 MB 5889 MB 134s
209+
* one program, grouping patched 1379 MB 3749 MB 53s
210+
* `tsc --noEmit`, whole package 1103 MB 1149 MB 18s
211+
*
212+
* The third row was measured with the grouping patched in a copy of tsup
213+
* outside this tree. It shows what cutting the program count is worth.
214+
*
215+
* NOT BYTE-STABLE: this pass does not emit the same bytes twice. TypeScript
216+
* prints union members, and the members of object types derived from them, in
217+
* type-creation order, and that order follows emit order. Three runs of the
218+
* same commit gave three different trees, and rollup's content-hashed chunk
219+
* names moved with them. Once union and property-signature order are
220+
* normalised, all three runs and the `noCheck` run are the same tree (128
221+
* files, 30389539 bytes). ⇒ Compare two declaration trees in such an
222+
* order-insensitive form, never by a byte digest.
193223
*
194224
* If this pass starts failing with `ERR_WORKER_OUT_OF_MEMORY`, the live type
195225
* graph has outgrown 6144 — that is a loud, actionable failure and the point of
196226
* the ceiling. ⛔ Do not "fix" it by raising the number past what the build
197-
* container has; that trades this error back for the silent exit 137. Shrink
198-
* the graph, or split the pass across entries.
227+
* container has; that trades this error back for the silent exit 137. Cut the
228+
* program count, shrink the graph, or split the pass across entries. Cutting
229+
* the count moves statement order and one chunk name beyond the noise above. A
230+
* split redraws the shared chunks. Either one changes what publishes, so it
231+
* needs that reviewed first.
199232
*/
200233
const isDts = process.env.BUILD_DTS === 'true';
201234

@@ -204,7 +237,8 @@ const mainConfig: Options = {
204237
splitting: false,
205238
sourcemap: true,
206239
clean: !isDts, // Only clean on main build, not on DTS pass
207-
dts: !isDts ? false : { only: true }, // Only generate DTS on explicit pass, without JS
240+
// Only generate DTS on the explicit pass, without JS; `noCheck` per the docblock above.
241+
dts: !isDts ? false : { only: true, compilerOptions: { noCheck: true } },
208242
format: ['esm', 'cjs'],
209243
target: 'es2020',
210244
treeshake: true,

0 commit comments

Comments
 (0)