Skip to content

Commit d8d6265

Browse files
fix(studio): resolve Chrome on Windows (#2878)
1 parent 6cab53a commit d8d6265

2 files changed

Lines changed: 40 additions & 7 deletions

File tree

packages/studio/vite.browser.test.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,27 @@
1-
import { beforeEach, describe, expect, it, vi } from "vitest";
1+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
22

33
const launch = vi.fn();
4+
const originalBrowserPath = process.env["HYPERFRAMES_BROWSER_PATH"];
45

56
vi.mock("puppeteer-core", () => ({
67
default: { launch },
78
}));
89

910
describe("generateThumbnail", () => {
1011
beforeEach(() => {
12+
process.env["HYPERFRAMES_BROWSER_PATH"] = process.execPath;
1113
launch.mockReset();
1214
launch.mockRejectedValue(new Error("browser launch failed"));
1315
});
1416

17+
afterEach(() => {
18+
if (originalBrowserPath === undefined) {
19+
delete process.env["HYPERFRAMES_BROWSER_PATH"];
20+
} else {
21+
process.env["HYPERFRAMES_BROWSER_PATH"] = originalBrowserPath;
22+
}
23+
});
24+
1525
it("contains browser launch failures and retries them on the next request", async () => {
1626
const { generateThumbnail } = await import("./vite.browser");
1727
const options = {
@@ -47,4 +57,12 @@ describe("findSystemChrome", () => {
4757
).toBe("/custom/browser");
4858
expect(pathExists).toHaveBeenCalledTimes(1);
4959
});
60+
61+
it("finds a standard Windows Chrome installation", async () => {
62+
const { findSystemChrome } = await import("./vite.browser");
63+
const chromePath = "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe";
64+
const pathExists = vi.fn((path: string) => path === chromePath);
65+
66+
expect(findSystemChrome({}, pathExists, "win32")).toBe(chromePath);
67+
});
5068
});

packages/studio/vite.browser.ts

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import { existsSync } from "node:fs";
44
import { createHash } from "node:crypto";
5+
import { win32 as pathWin32 } from "node:path";
56
import {
67
createStudioDevRenderBodyScripts,
78
readStudioDevManualEditManifestContent,
@@ -14,20 +15,34 @@ import { seekThumbnailPreview } from "./vite.thumbnail";
1415
let _browser: import("puppeteer-core").Browser | null = null;
1516
let _browserLaunchPromise: Promise<import("puppeteer-core").Browser> | null = null;
1617

17-
const CHROME_PATHS = [
18-
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
19-
"/usr/bin/google-chrome",
20-
"/usr/bin/chromium-browser",
21-
];
18+
function systemChromePaths(env: NodeJS.ProcessEnv, platform: NodeJS.Platform): string[] {
19+
if (platform === "win32") {
20+
const programFiles = env["PROGRAMFILES"] ?? "C:\\Program Files";
21+
const programFilesX86 = env["PROGRAMFILES(X86)"] ?? "C:\\Program Files (x86)";
22+
const localAppData = env["LOCALAPPDATA"];
23+
return [
24+
pathWin32.join(programFiles, "Google", "Chrome", "Application", "chrome.exe"),
25+
pathWin32.join(programFilesX86, "Google", "Chrome", "Application", "chrome.exe"),
26+
...(localAppData
27+
? [pathWin32.join(localAppData, "Google", "Chrome", "Application", "chrome.exe")]
28+
: []),
29+
];
30+
}
31+
if (platform === "darwin") {
32+
return ["/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"];
33+
}
34+
return ["/usr/bin/google-chrome", "/usr/bin/chromium-browser"];
35+
}
2236

2337
/** Resolve the same explicit browser overrides used by the CLI before system paths. */
2438
export function findSystemChrome(
2539
env: NodeJS.ProcessEnv = process.env,
2640
pathExists: (path: string) => boolean = existsSync,
41+
platform: NodeJS.Platform = process.platform,
2742
): string | undefined {
2843
const override = env["HYPERFRAMES_BROWSER_PATH"] ?? env["PRODUCER_HEADLESS_SHELL_PATH"];
2944
if (override && pathExists(override)) return override;
30-
return CHROME_PATHS.find((path) => pathExists(path));
45+
return systemChromePaths(env, platform).find((path) => pathExists(path));
3146
}
3247

3348
async function getSharedBrowser(): Promise<import("puppeteer-core").Browser | null> {

0 commit comments

Comments
 (0)