mirror of https://github.com/garrytan/gstack.git
fix(browse): stop the Bun polyfill flashing console windows on Windows
The Node bun-polyfill forwards Bun.spawn/spawnSync to child_process without windowsHide. Node defaults that option to false, so on Windows every child the browse server starts opens a console window -- Bun itself does not behave this way, so the polyfill was drifting from the API it emulates. The visible symptom is an empty black bun.exe window appearing every ~60s: server.ts's agent watchdog respawns a crashed terminal-agent on each tick, and the agent is spawned with stdio ['ignore','ignore', 'ignore'], so the window it opens has nothing in it. The tasklist, powershell and chrome --version helpers pop windows the same way. Fixed at the polyfill rather than the call sites, since it is the one choke point every Bun.spawn under Node passes through. An explicit windowsHide: false is still honoured for callers that want a visible console. Verified against the unpatched polyfill (spawn/spawnSync both received undefined) and the patched one (both receive true, explicit false still wins). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
a3259400a3
commit
052c7fe010
|
|
@ -75,6 +75,10 @@ globalThis.Bun = {
|
|||
timeout: options.timeout,
|
||||
env: options.env,
|
||||
cwd: options.cwd,
|
||||
// Node defaults windowsHide to false, so every child opens a console
|
||||
// window on Windows. Bun.spawnSync has no such behaviour, so the
|
||||
// polyfill has to opt in to stay faithful to the API it's emulating.
|
||||
windowsHide: options.windowsHide !== false,
|
||||
});
|
||||
|
||||
return {
|
||||
|
|
@ -91,6 +95,10 @@ globalThis.Bun = {
|
|||
stdio,
|
||||
env: options.env,
|
||||
cwd: options.cwd,
|
||||
// See spawnSync above. This one is the visible offender: the detached
|
||||
// terminal-agent the browse watchdog respawns every 60s left an empty
|
||||
// console window on screen each time.
|
||||
windowsHide: options.windowsHide !== false,
|
||||
});
|
||||
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -48,6 +48,44 @@ describe('bun-polyfill', () => {
|
|||
expect(lines[2]).toBe('HAS_UNREF');
|
||||
});
|
||||
|
||||
// Regression: Node defaults windowsHide to false, so before this the browse
|
||||
// server flashed an empty console window on Windows for every child it
|
||||
// spawned -- most visibly the terminal-agent the watchdog respawns on a 60s
|
||||
// tick. Asserts the option reaches child_process rather than trying to
|
||||
// observe a window, so it is meaningful on every platform.
|
||||
test('Bun.spawn/spawnSync pass windowsHide to child_process', () => {
|
||||
const result = Bun.spawnSync(['node', '-e', `
|
||||
const cp = require('child_process');
|
||||
const realSpawn = cp.spawn, realSpawnSync = cp.spawnSync;
|
||||
const seen = {};
|
||||
cp.spawn = (c, a, o) => { seen.spawn = o.windowsHide; return realSpawn(c, a, o); };
|
||||
cp.spawnSync = (c, a, o) => { seen.spawnSync = o.windowsHide; return realSpawnSync(c, a, o); };
|
||||
require('${polyfillPath}');
|
||||
Bun.spawnSync([process.execPath, '-e', ''], { stdout: 'pipe' });
|
||||
Bun.spawn([process.execPath, '-e', ''], { stdio: ['ignore', 'ignore', 'ignore'] });
|
||||
console.log('spawnSync:' + seen.spawnSync);
|
||||
console.log('spawn:' + seen.spawn);
|
||||
`], { stdout: 'pipe', stderr: 'pipe' });
|
||||
const lines = result.stdout.toString().trim().split('\n');
|
||||
expect(lines[0]).toBe('spawnSync:true');
|
||||
expect(lines[1]).toBe('spawn:true');
|
||||
});
|
||||
|
||||
// An explicit windowsHide: false must still win, so a caller that genuinely
|
||||
// wants a visible console (e.g. debugging a child) keeps that escape hatch.
|
||||
test('Bun.spawn honours an explicit windowsHide: false', () => {
|
||||
const result = Bun.spawnSync(['node', '-e', `
|
||||
const cp = require('child_process');
|
||||
const realSpawn = cp.spawn;
|
||||
const seen = {};
|
||||
cp.spawn = (c, a, o) => { seen.spawn = o.windowsHide; return realSpawn(c, a, o); };
|
||||
require('${polyfillPath}');
|
||||
Bun.spawn([process.execPath, '-e', ''], { stdio: ['ignore', 'ignore', 'ignore'], windowsHide: false });
|
||||
console.log('spawn:' + seen.spawn);
|
||||
`], { stdout: 'pipe', stderr: 'pipe' });
|
||||
expect(result.stdout.toString().trim()).toBe('spawn:false');
|
||||
});
|
||||
|
||||
test('Bun.serve creates an HTTP server that responds', async () => {
|
||||
const result = Bun.spawnSync(['node', '-e', `
|
||||
require('${polyfillPath}');
|
||||
|
|
|
|||
Loading…
Reference in New Issue