From 3dc08c0868ba053b9bf8b8739947d0864137dac2 Mon Sep 17 00:00:00 2001 From: Vance Ingalls Date: Sat, 11 Jul 2026 12:28:34 -0700 Subject: [PATCH] feat(cli): preview --browser-no-gpu for gpu-unstable hosts --- packages/cli/src/commands/preview.ts | 19 +++++++++++++++++++ packages/cli/src/utils/openBrowser.test.ts | 13 +++++++++++++ packages/cli/src/utils/openBrowser.ts | 11 +++++++++++ 3 files changed, 43 insertions(+) diff --git a/packages/cli/src/commands/preview.ts b/packages/cli/src/commands/preview.ts index 6edeec423a..b3f6cd5ed8 100644 --- a/packages/cli/src/commands/preview.ts +++ b/packages/cli/src/commands/preview.ts @@ -50,6 +50,7 @@ interface BrowserLaunchOptions { browserPath?: string; userDataDir?: string; remoteDebuggingPort?: number; + browserNoGpu?: boolean; } interface StudioLaunchOptions extends BrowserLaunchOptions { @@ -142,6 +143,12 @@ export default defineCommand({ type: "string", description: "Chromium remote debugging port (requires --browser-path and --user-data-dir)", }, + "browser-no-gpu": { + type: "boolean", + default: false, + description: + "Launch the opened browser with --disable-gpu (requires --browser-path). For hosts where hardware acceleration crashes the graphics driver (e.g. NVIDIA Xid resets); with the system default browser use --no-open instead.", + }, }, async run({ args }) { const startPort = parseInt(args.port ?? "3002", 10); @@ -239,6 +246,14 @@ export default defineCommand({ const noOpen = !args.open; const browserPath = args["browser-path"] as string | undefined; + const browserNoGpu = !!args["browser-no-gpu"]; + if (browserNoGpu && !browserPath) { + clack.log.error( + "--browser-no-gpu requires --browser-path (the system default browser cannot receive Chromium flags — use --no-open on GPU-unstable hosts)", + ); + process.exitCode = 1; + return; + } const userDataDir = args["user-data-dir"] as string | undefined; let remoteDebuggingPort: number | undefined; try { @@ -258,6 +273,7 @@ export default defineCommand({ browserPath, userDataDir, remoteDebuggingPort, + browserNoGpu, }); } @@ -269,6 +285,7 @@ export default defineCommand({ browserPath, userDataDir, remoteDebuggingPort, + browserNoGpu, }); } @@ -280,6 +297,7 @@ export default defineCommand({ browserPath, userDataDir, remoteDebuggingPort, + browserNoGpu, }); }, }); @@ -641,6 +659,7 @@ function openStudioBrowser(url: string, projectName: string, options?: BrowserLa browserPath: options?.browserPath, userDataDir: options?.userDataDir, remoteDebuggingPort: options?.remoteDebuggingPort, + disableGpu: options?.browserNoGpu, }); } diff --git a/packages/cli/src/utils/openBrowser.test.ts b/packages/cli/src/utils/openBrowser.test.ts index 3de1f307b4..7dbe859d4f 100644 --- a/packages/cli/src/utils/openBrowser.test.ts +++ b/packages/cli/src/utils/openBrowser.test.ts @@ -158,3 +158,16 @@ describe("validateRemoteDebuggingPortDeps", () => { ).toBe("--remote-debugging-port requires --browser-path"); }); }); + +describe("buildBrowserArgs --disable-gpu", () => { + it("appends --disable-gpu before the url when disableGpu is set", () => { + expect(buildBrowserArgs("http://localhost:3002", { disableGpu: true })).toEqual([ + "--disable-gpu", + "http://localhost:3002", + ]); + }); + + it("omits --disable-gpu by default", () => { + expect(buildBrowserArgs("http://localhost:3002", {})).toEqual(["http://localhost:3002"]); + }); +}); diff --git a/packages/cli/src/utils/openBrowser.ts b/packages/cli/src/utils/openBrowser.ts index 1bb3ad9b33..0cde28af9d 100644 --- a/packages/cli/src/utils/openBrowser.ts +++ b/packages/cli/src/utils/openBrowser.ts @@ -4,6 +4,14 @@ export interface OpenBrowserOptions { browserPath?: string; userDataDir?: string; remoteDebuggingPort?: number; + /** + * Launch the browser with --disable-gpu. For hosts where hardware + * acceleration crashes the graphics driver (wild report: auto-opened + * preview triggered NVIDIA Xid 32 resets on NixOS). Only effective with + * `browserPath` — the `open`-package fallback launches the system default + * browser with no way to pass Chromium flags. + */ + disableGpu?: boolean; } export function parseRemoteDebuggingPort(value: string | undefined): number | undefined { @@ -52,6 +60,9 @@ export function buildBrowserArgs(url: string, options: OpenBrowserOptions): stri if (options.remoteDebuggingPort !== undefined && options.userDataDir) { args.push(`--remote-debugging-port=${options.remoteDebuggingPort}`); } + if (options.disableGpu) { + args.push("--disable-gpu"); + } args.push(url); return args; }