Skip to content

Commit eb72841

Browse files
authored
Merge pull request #11187 from quarto-dev/fix/chrome
2 parents e928dd8 + d629028 commit eb72841

File tree

3 files changed

+38
-4
lines changed

3 files changed

+38
-4
lines changed

news/changelog-1.6.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,11 @@ All changes included in 1.6:
105105

106106
- ([#9134](https://github.com/quarto-dev/quarto-cli/issues/9134)): Add proper fix for `multiprocessing` in notebooks with the Python kernel.
107107

108+
## Chromium support
109+
110+
- ([#11135](https://github.com/quarto-dev/quarto-cli/issues/11135)): Use `--headless=old` mode for Chromium to avoid recent issues with the new `--headless` mode. Setting `--headless=new` can be configured with `QUARTO_CHROMIUM_HEADLESS_MODE=new` environment variable, however it is not recommended new headless mode seems to be unstable. Only use to be unblocked of a situation (like `QUARTO_CHROMIUM_HEADLESS_MODE="none"` if you use an old chrome version somehow that don't support `--headless=old`).
111+
- ([#10170](https://github.com/quarto-dev/quarto-cli/issues/10170)): Quarto should find chrome executable automatically on most OS. If this is does not find it, or a specific version is needed, set `QUARTO_CHROMIUM` environment variable to the executable path.
112+
108113
## Other Fixes and Improvements
109114

110115
- Upgrade `mermaidjs` to 11.2.0.

src/core/cri/cri.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ import { findOpenPort } from "../port.ts";
1414
import { getNamedLifetime, ObjectWithLifetime } from "../lifetimes.ts";
1515
import { sleep } from "../async.ts";
1616
import { InternalError } from "../lib/error.ts";
17+
import { getenv } from "../env.ts";
1718
import { kRenderFileLifetime } from "../../config/constants.ts";
19+
import { debug } from "../../deno_ral/log.ts";
1820

1921
async function waitForServer(port: number, timeout = 3000) {
2022
const interval = 50;
@@ -78,9 +80,20 @@ export async function criClient(appPath?: string, port?: number) {
7880
}
7981
const app: string = appPath || await getBrowserExecutablePath();
8082

83+
// Allow to adapt the headless mode depending on the Chrome version
84+
const headlessMode = getenv("QUARTO_CHROMIUM_HEADLESS_MODE", "old");
85+
8186
const cmd = [
8287
app,
83-
"--headless",
88+
// TODO: Chrome v128 changed the default from --headless=old to --headless=new
89+
// in 2024-08. Old headless mode was effectively a separate browser render,
90+
// and while more performant did not share the same browser implementation as
91+
// headful Chrome. New headless mode will likely be useful to some, but in Quarto use cases
92+
// like printing to PDF or screenshoting, we need more work to
93+
// move to the new mode. We'll use `--headless=old` as the default for now
94+
// until the new mode is more stable, or until we really pin a version as default to be used.
95+
// This is also impacting in chromote and pagedown R packages and we could keep syncing with them.
96+
`--headless${headlessMode == "none" ? "" : "=" + headlessMode}`,
8497
"--no-sandbox",
8598
"--disable-gpu",
8699
"--renderer-process-limit=1",
@@ -92,6 +105,8 @@ export async function criClient(appPath?: string, port?: number) {
92105
let msg = "Couldn't find open server.";
93106
// Printing more error information if chrome process errored
94107
if (!(await browser.status()).success) {
108+
debug(`[CHROMIUM path] : ${app}`);
109+
debug(`[CHROMIUM cmd] : ${cmd}`);
95110
const rawError = await browser.stderrOutput();
96111
const errorString = new TextDecoder().decode(rawError);
97112
msg = msg + "\n" + `Chrome process error: ${errorString}`;

src/core/puppeteer.ts

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
import { readRegistryKey } from "./windows.ts";
88
import { safeExistsSync, which } from "./path.ts";
9-
import { error, info } from "../deno_ral/log.ts";
9+
import { debug, error, info } from "../deno_ral/log.ts";
1010
import { existsSync } from "../deno_ral/fs.ts";
1111
import { UnreachableError } from "./lib/error.ts";
1212
import { quartoDataDir } from "./appdirs.ts";
@@ -201,12 +201,20 @@ export async function withHeadlessBrowser<T>(
201201

202202
async function findChrome(): Promise<string | undefined> {
203203
let path;
204+
// First check env var and use this path if specified
205+
const envPath = Deno.env.get("QUARTO_CHROMIUM");
206+
if (envPath && safeExistsSync(envPath)) {
207+
debug("[CHROMIUM] Using path specified in QUARTO_CHROMIUM");
208+
debug(`[CHROMIUM] Path: ${envPath}`);
209+
return envPath;
210+
}
211+
// Otherwise, try to find the path based on OS.
204212
if (Deno.build.os === "darwin") {
205213
const programs = [
206214
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
207215
"/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge",
208216
];
209-
return programs.find(safeExistsSync);
217+
path = programs.find(safeExistsSync);
210218
} else if (Deno.build.os === "windows") {
211219
// Try the HKLM key
212220
const programs = ["chrome.exe", "msedge.exe"];
@@ -216,7 +224,7 @@ async function findChrome(): Promise<string | undefined> {
216224
programs[i],
217225
"(Default)",
218226
);
219-
if (path && existsSync(path)) break;
227+
if (path && safeExistsSync(path)) break;
220228
}
221229

222230
// Try the HKCR key
@@ -240,6 +248,12 @@ async function findChrome(): Promise<string | undefined> {
240248
path = await which("chromium-browser");
241249
}
242250
}
251+
if (path) {
252+
debug("[CHROMIUM] Found Chromium on OS known location");
253+
debug(`[CHROMIUM] Path: ${path}`);
254+
} else {
255+
debug("[CHROMIUM] Chromium not found on OS known location");
256+
}
243257
return path;
244258
}
245259

0 commit comments

Comments
 (0)