worker_threads: keep the native console in workers, routed through process.stdout/stderr
What does this PR do?
Since #31216 a node:worker_threads worker replaces globalThis.console with a JS Console bound to its port-backed process.stdout/process.stderr, so that the parent's worker.stdout sees console output. Building that Console loads node:console, node:util, internal/util/inspect, node:url (+ a few small deps) on every worker thread — each parsed from source again — and it makes a worker's console format differently from the main thread's.
Now the worker keeps Bun's native console. Once its stdio is port-backed, the bootstrap flips a flag on the VM's console; from then on the console formats as it always does (uncolored — those streams aren't TTYs) into a buffer and hands the bytes to process.stdout / process.stderr. So:
- capture (
{ stdout: true }/worker.stdout), auto-piping to the parent, and ordering relative toprocess.stdout.write()are unchanged; count/timeLog/timeEnd/assert/table/trace/grouptake the same route;console.clearis a no-op in a worker (its stdio isn't the terminal);- a failing or ended stream never makes
console.log()throw, as with Node'sConsole(ignoreErrors); - none of
node:console/node:util/internal/util/inspect/node:urlload in a worker unless user code asks for them.
Visible difference: objects logged from a worker are formatted the way the main thread (and Bun ≤ 1.3.x workers) formats them, not in util.inspect style; console.write exists in workers again.
Local release build, new Worker → first message: 7.6 → 6.5 ms; a worker that also console.logs: 11 → 7.0 ms. Follows #39536.
How did you verify your code works?
test/js/node/worker_threads/*.test.ts (137/137, incl. the captured-stdio and exit-flush cases), test/js/web/workers/worker.test.ts, node test-worker-* / worker-using test-console-* / test-process-* files match main. Drove every console method plus a throwing / ended process.stdout in a captured worker on the debug build with BUN_JSC_validateExceptionChecks=1.