Files
orca/config/scripts/pinned-bun-executable.mjs
T
Neil dcfe8c9e6c perf(typecheck): pin Bun as a devDependency and typecheck with it (#30149)
* perf(typecheck): pnpm tc uses the pinned Bun checker when available

bun check (Bun 1.4.3, TypeScript 7.0.2 parity, already used by CI) checks the
node project in ~29 CPU-s / ~2 GB peak vs tsc's ~98 CPU-s / ~16.6 GB. tsc's
incremental cache rarely helps agents: noEmit builds store no declaration
signatures, so the first edit to any file after a cold check re-checks every
transitive importer (a comment in src/shared/constants.ts re-checks all 18k files).

pnpm tc / tc:node / tc:web / tc:cli now pick the Bun from config/.bun-version when
it is on PATH and fall back to tsc with a one-line hint otherwise;
--compiler=native forces tsc. The pinned-Bun probe is shared with the
localization extraction check.

* build: pin Bun as a devDependency and make it the only default checker

The PATH probe left anyone without the exact pinned Bun (including a 1.4.2
global) on tsc's expensive path. bun@1.4.3 is now a devDependency, its
postinstall is allowed, and pnpm tc / typecheck:ci run that binary. A missing
binary is an error pointing at pnpm install rather than a silent fallback;
--compiler=native still selects tsc. A test keeps the devDependency equal to
config/.bun-version.

* ci: link the pinned Bun after the script-free install

--ignore-scripts leaves node_modules/.bin/bun as bun's postinstall stub, so the
typecheck runner found no binary and any pnpm-run script calling bun would hit
the stub before setup-bun's copy. pnpm rebuild bun runs only that allowed build.
2026-10-17 22:43:00 -07:00

36 lines
1.1 KiB
JavaScript

import { readFileSync } from 'node:fs'
import { createRequire } from 'node:module'
import path from 'node:path'
export function readPinnedBunVersion(root) {
return readFileSync(path.join(root, 'config', '.bun-version'), 'utf8').trim()
}
/**
* Absolute path of the `bun` devDependency when it runs and is exactly the version in
* config/.bun-version, otherwise null. Its binary is only real once the postinstall ran.
*/
export function resolvePinnedBunExecutable(root, runProcessSync) {
try {
const manifestPath = createRequire(path.join(root, 'package.json')).resolve('bun/package.json')
const { bin } = JSON.parse(readFileSync(manifestPath, 'utf8'))
const executable = path.join(path.dirname(manifestPath), bin.bun)
const probe = runProcessSync({
program: executable,
args: ['--version'],
cwd: root,
env: process.env,
timeoutMs: 2000,
maxOutputBytes: 4096
})
return probe.code === 0 &&
!probe.signal &&
!probe.timedOut &&
probe.stdout.trim() === readPinnedBunVersion(root)
? executable
: null
} catch {
return null
}
}