From 14dcb78ee80abbece20cecbbe5abd0d1d7fbf214 Mon Sep 17 00:00:00 2001 From: Turtle 2099 Date: Mon, 19 Oct 2026 19:12:07 +0800 Subject: [PATCH] fix(ci): split the Wine Host compile to fit its heap budget (#6578) The Wine gate compiled the Host face with one `tsc -b tsconfig.host.json`, which holds the project-reference graph and the aggregate program in a single V8 process and aborted at 4063.4 of 4088.3 MB. The supported build splits those steps, and the native Windows build in the same run compiled the references at 4096 and reached the aggregate without running out of memory. Compile the referenced projects first, then type-check the aggregate, both at 4096. Assert the two commands and their order, and reject the fused invocation. Co-authored-by: turtle1999 --- scripts/ci-workflow.spec.ts | 13 +++++++++---- scripts/wine-windows-gates.sh | 11 ++++++++--- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/scripts/ci-workflow.spec.ts b/scripts/ci-workflow.spec.ts index 1040b5f18b..e30512816e 100644 --- a/scripts/ci-workflow.spec.ts +++ b/scripts/ci-workflow.spec.ts @@ -671,15 +671,20 @@ describe('CI workflow', () => { expect(uploadIndex).toBeGreaterThan(benchmarkIndex) }) - it('generates metadata before the Wine Host TypeScript compile and retains its heap budget', () => { + it('splits the Wine Host TypeScript compile and retains its heap budget', () => { const wineGates = readFileSync(resolve(root, 'scripts/wine-windows-gates.sh'), 'utf8') - expect(wineGates).toContain( - 'wine_node "$scratch/logs/host-tsc.log" --max-old-space-size=4096 "$tsc_js" -b tsconfig.host.json --pretty false', + const references = wineGates.indexOf( + 'wine_node "$scratch/logs/host-references.log" --import tsx/esm scripts/compile-referenced-projects.ts host', + ) + const aggregate = wineGates.indexOf( + 'wine_node "$scratch/logs/host-tsc.log" --max-old-space-size=4096 "$tsc_js" -p tsconfig.host.json --pretty false', ) const metadata = wineGates.indexOf('wine_node "$scratch/logs/host-typert.log" --import tsx/esm scripts/generate-typert.ts') expect(metadata).toBeGreaterThan(-1) - expect(metadata).toBeLessThan(wineGates.indexOf('wine_node "$scratch/logs/host-tsc.log"')) + expect(references).toBeGreaterThan(metadata) + expect(aggregate).toBeGreaterThan(references) + expect(wineGates).not.toContain('-b tsconfig.host.json') }) it('cancels superseded master runs without changing the post-merge job inventory', () => { diff --git a/scripts/wine-windows-gates.sh b/scripts/wine-windows-gates.sh index 785d6b1d2d..3e2c0ef291 100755 --- a/scripts/wine-windows-gates.sh +++ b/scripts/wine-windows-gates.sh @@ -243,12 +243,17 @@ grep -q '^smoke: win32 x64' "$scratch/logs/smoke.log" || { echo 'wine-windows-ga # ---- the two blocking surfaces, concurrently ------------------------------ # The build mirrors the root build:lib:host and build:lib:client scripts: -# generate metadata, compile and bundle the Host face, bundle apps/desktop from -# the Host lib/ outputs, then compile and bundle the Client face. +# generate metadata, compile the Host package projects, type-check the Host +# aggregate program, bundle the Host face, bundle apps/desktop from the Host +# lib/ outputs, then compile and bundle the Client face. The Host compile is two +# invocations because that is how the supported build splits it; a single +# `tsc -b` holds the reference graph and the aggregate program in one process +# and exceeds the heap the Host face is budgeted. # Both statuses are captured so one failure cannot hide the other's result. build_gate() { wine_node "$scratch/logs/host-typert.log" --import tsx/esm scripts/generate-typert.ts || return $? - wine_node "$scratch/logs/host-tsc.log" --max-old-space-size=4096 "$tsc_js" -b tsconfig.host.json --pretty false || return $? + wine_node "$scratch/logs/host-references.log" --import tsx/esm scripts/compile-referenced-projects.ts host || return $? + wine_node "$scratch/logs/host-tsc.log" --max-old-space-size=4096 "$tsc_js" -p tsconfig.host.json --pretty false || return $? wine_node "$scratch/logs/host-tsdown.log" "$tsdown_js" --env.DSH_BUILD_FACE host || return $? (cd apps/desktop && wine_node "$scratch/logs/desktop-tsdown.log" "../../$tsdown_js") || return $? wine_node "$scratch/logs/client-tsc.log" "$tsc_js" -b tsconfig.client.json --pretty false || return $?