From 66c22b1fc506128e18174556fb3e86b27ba6c01b Mon Sep 17 00:00:00 2001 From: Tim van der Meij Date: Sun, 14 Jun 2026 16:26:18 +0200 Subject: [PATCH 1/3] Configure Puppeteer to not download Chrome headless shell Nowadays Chrome has a built-in (new) headless mode in the regular binary, but before that time there was an old headless mode that was essentially a separate binary [1]. We don't use the latter, but it turns out that Puppeteer downloads it automatically if it's not explicitly skipped, which is wasteful because it costs extra time and resources for each `npm install` invocation. This commit therefore skips downloading Chrome headless shell explictly, which results in the local runtime of `npm install` going from 10.125 seconds to 8.998 seconds (which can't hurt in e.g. GitHub Actions). [1] https://developer.chrome.com/blog/chrome-headless-shell. --- .puppeteerrc.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.puppeteerrc.json b/.puppeteerrc.json index 4457c47d7..d45a2f2fd 100644 --- a/.puppeteerrc.json +++ b/.puppeteerrc.json @@ -2,6 +2,9 @@ "chrome": { "skipDownload": false }, + "chrome-headless-shell": { + "skipDownload": true + }, "firefox": { "skipDownload": false, "version": "nightly" From 6bfefa53da24ccbf703ea8f22380e60f718aa107 Mon Sep 17 00:00:00 2001 From: Tim van der Meij Date: Sun, 14 Jun 2026 16:28:36 +0200 Subject: [PATCH 2/3] Configure Puppeteer to use the stable version of Chrome We currently use the pinned version of Chrome as hardcoded in the Puppeteer release, which is based on the version of Chrome that was deemed stable at the time of the Puppeteer release. However, this is not ideal because it means that Chrome updates are strongly tied to Puppeteer releases, so if Puppeteer releases are slow we could be missing out on e.g. (security) patches being applied on the stable channel. It's also not consistent with Firefox where we don't use a hardcoded pinned version either. This commit therefore configures Puppeteer to use (resolve) the most recent stable version of Chrome at the time of the installation so that determining the browser version to use is fully decoupled from the Puppeteer release we're running. The effect of this change can be seen in the output of running `npx puppeteer browsers list`: Before: `chrome@149.0.7827.22 (linux) ` After (note the slightly newer version): `chrome@149.0.7827.115 (linux)` ` --- .puppeteerrc.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.puppeteerrc.json b/.puppeteerrc.json index d45a2f2fd..4401066f6 100644 --- a/.puppeteerrc.json +++ b/.puppeteerrc.json @@ -1,6 +1,7 @@ { "chrome": { - "skipDownload": false + "skipDownload": false, + "version": "stable" }, "chrome-headless-shell": { "skipDownload": true From 26b4206d879673f8e2cbbb615b59bb211c8ea3fc Mon Sep 17 00:00:00 2001 From: Tim van der Meij Date: Sun, 14 Jun 2026 16:23:43 +0200 Subject: [PATCH 3/3] Configure Puppeteeer to not download Chrome/Firefox by default We currently download Chrome/Firefox immediately on `npm install` invocations because Puppeteer's postinstall script does that by default. However, this is wasteful if the user/workflow doesn't actually need to run Puppeteer or its browsers, for example in GitHub Actions workflows that do linting, static analysis or other tasks like updating locales or publishing artifacts. This commit therefore makes sure no browser binaries get pulled in by default anymore, and defers doing that until it's actually necessary, which is when we want to start the browsers in the `startBrowsers` function of `test.mjs`. Locally this brings the `npm install` runtime down from 8.998 to 1.800 seconds, and as a bonus it results in better log output too because it now shows which browser versions were used in the run (whereas previously with `npm install` this information was not sent to stdout). --- .puppeteerrc.json | 4 ++-- test/test.mjs | 11 ++++++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/.puppeteerrc.json b/.puppeteerrc.json index 4401066f6..a1d055219 100644 --- a/.puppeteerrc.json +++ b/.puppeteerrc.json @@ -1,13 +1,13 @@ { "chrome": { - "skipDownload": false, + "skipDownload": true, "version": "stable" }, "chrome-headless-shell": { "skipDownload": true }, "firefox": { - "skipDownload": false, + "skipDownload": true, "version": "nightly" } } diff --git a/test/test.mjs b/test/test.mjs index e35a0e2c6..a2a1a733b 100644 --- a/test/test.mjs +++ b/test/test.mjs @@ -28,6 +28,7 @@ import { downloadManifestFiles, verifyManifestFiles, } from "./downloadutils.mjs"; +import { execSync } from "child_process"; import fs from "fs"; import istanbulCoverage from "istanbul-lib-coverage"; import istanbulReportGenerator from "istanbul-reports"; @@ -1095,9 +1096,13 @@ async function startBrowser({ } async function startBrowsers({ baseUrl, initializeSession, numSessions = 1 }) { - // Remove old browser revisions from Puppeteer's cache. Updating Puppeteer can - // cause new browser revisions to be downloaded, so trimming the cache will - // prevent the disk from filling up over time. + // Install the browsers. + for (const browser of ["firefox@nightly", "chrome@stable"]) { + execSync(`npx puppeteer browsers install ${browser}`, { stdio: "inherit" }); + } + + // Remove old browser revisions from Puppeteer's cache. The commands above can + // download new browser revisions, so this prevents the disk from filling up. await puppeteer.trimCache(); const browserNames = ["firefox", "chrome"];