From 49c11f0cea990054ce35377b3ceb2eff5d63b480 Mon Sep 17 00:00:00 2001 From: Randi <55005611+rdself@users.noreply.github.com> Date: Mon, 8 Jun 2026 22:34:07 -0400 Subject: [PATCH] fix(browser): avoid bundling optional cloakbrowser import (#3460) Integrated into release/v3.8.17 --- open-sse/services/browserPool.ts | 15 +++++++++-- .../unit/browser-pool-optional-import.test.ts | 27 +++++++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 tests/unit/browser-pool-optional-import.test.ts diff --git a/open-sse/services/browserPool.ts b/open-sse/services/browserPool.ts index 9523edc912..e72862e805 100644 --- a/open-sse/services/browserPool.ts +++ b/open-sse/services/browserPool.ts @@ -78,11 +78,17 @@ const state: PoolState = { cloakLaunchResolved: false, }; +function getCloakbrowserModuleId(): string { + // Keep this computed: cloakbrowser is an optional runtime enhancer, and a literal + // dynamic import with the package name makes Turbopack resolve it during route compilation. + return ["cloak", "browser"].join(""); +} + async function resolveCloakLaunch(): Promise<((opts: unknown) => Promise) | null> { if (state.cloakLaunchResolved) return state.cloakLaunch; state.cloakLaunchResolved = true; try { - const mod = (await import("cloakbrowser")) as unknown as { + const mod = (await import(getCloakbrowserModuleId())) as unknown as { launch?: (opts: unknown) => Promise; }; state.cloakLaunch = mod.launch ?? null; @@ -110,7 +116,12 @@ function evictStaleContexts(): void { const now = Date.now(); for (const [key, pooled] of state.contexts) { if (now - pooled.lastUsed > CONTEXT_TTL_MS) { - console.log("[BrowserPool] Evicted stale context:", key, "(idle", ((now - pooled.lastUsed) / 1000).toFixed(0) + "s)"); + console.log( + "[BrowserPool] Evicted stale context:", + key, + "(idle", + ((now - pooled.lastUsed) / 1000).toFixed(0) + "s)" + ); state.contexts.delete(key); pooled.context.close().catch(() => {}); } diff --git a/tests/unit/browser-pool-optional-import.test.ts b/tests/unit/browser-pool-optional-import.test.ts new file mode 100644 index 0000000000..2e9f68390f --- /dev/null +++ b/tests/unit/browser-pool-optional-import.test.ts @@ -0,0 +1,27 @@ +import assert from "node:assert/strict"; +import { readFileSync } from "node:fs"; +import path from "node:path"; +import { describe, it } from "node:test"; +import { fileURLToPath } from "node:url"; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const REPO_ROOT = path.resolve(__dirname, "../.."); +const BROWSER_POOL_PATH = path.join(REPO_ROOT, "open-sse/services/browserPool.ts"); + +describe("browserPool optional cloakbrowser import", () => { + it("keeps cloakbrowser out of static dynamic import resolution", () => { + const source = readFileSync(BROWSER_POOL_PATH, "utf8"); + + assert.equal( + /import\(\s*["']cloakbrowser["']\s*\)/.test(source), + false, + "cloakbrowser must remain runtime-optional; static dynamic import triggers Turbopack resolution" + ); + assert.match( + source, + /Turbopack resolve it during route compilation/, + "the computed import rationale should stay documented near the helper" + ); + assert.match(source, /return \["cloak", "browser"\]\.join\(""\);/); + }); +});