From 903dec8cfcfaf247f3413969356c493d264bf3c3 Mon Sep 17 00:00:00 2001 From: abdolrhman-mo Date: Tue, 24 Mar 2026 13:23:35 +0200 Subject: [PATCH] fix(browse): use detached child_process.spawn on Windows for server persistence MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bun.spawn() with proc.unref() on Windows doesn't truly detach the server subprocess — it dies when the CLI parent exits. This caused every $B command to start a fresh Chromium instance at about:blank, making the browse binary completely non-functional on Windows. Fix: On Windows, use Node's child_process.spawn with { detached: true, stdio: 'ignore' } which creates a truly independent process that survives parent exit. Tested on Windows 11 with Next.js 16 + Turbopack: - Server persists between commands (no more "[browse] Starting server..." on every call) - Pages render with full interactive elements - goto + url returns the correct URL instead of about:blank Co-Authored-By: Claude Opus 4.6 (1M context) --- browse/src/cli.ts | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/browse/src/cli.ts b/browse/src/cli.ts index 830b2e7ca..3e9af95dc 100644 --- a/browse/src/cli.ts +++ b/browse/src/cli.ts @@ -170,17 +170,31 @@ async function startServer(): Promise { // Start server as detached background process. // On Windows, Bun can't launch/connect to Playwright's Chromium (oven-sh/bun#4253, #9911). // Fall back to running the server under Node.js with Bun API polyfills. + // Additionally, Bun.spawn + unref() on Windows doesn't truly detach — the child dies + // when the CLI parent exits. Use Node's child_process.spawn with detached:true instead. const useNode = IS_WINDOWS && NODE_SERVER_SCRIPT; const serverCmd = useNode ? ['node', NODE_SERVER_SCRIPT] : ['bun', 'run', SERVER_SCRIPT]; - const proc = Bun.spawn(serverCmd, { - stdio: ['ignore', 'pipe', 'pipe'], - env: { ...process.env, BROWSE_STATE_FILE: config.stateFile }, - }); - // Don't hold the CLI open - proc.unref(); + if (IS_WINDOWS) { + // On Windows, Bun.spawn's unref() doesn't create a truly detached process. + // The server dies when the CLI exits. Use Node's child_process.spawn instead. + const { spawn: nodeSpawn } = require('child_process'); + const child = nodeSpawn(serverCmd[0], serverCmd.slice(1), { + detached: true, + stdio: 'ignore', + env: { ...process.env, BROWSE_STATE_FILE: config.stateFile }, + }); + child.unref(); + } else { + const proc = Bun.spawn(serverCmd, { + stdio: ['ignore', 'pipe', 'pipe'], + env: { ...process.env, BROWSE_STATE_FILE: config.stateFile }, + }); + // Don't hold the CLI open + proc.unref(); + } // Wait for state file to appear const start = Date.now();