Skip to content

fix(browse): bump Playwright to ^1.60.0 and pin full Chromium for extension loading#1565

Open
stevenbarragan wants to merge 1 commit into
garrytan:mainfrom
stevenbarragan:stevenbarragan/pin-chromium-launch-headed
Open

fix(browse): bump Playwright to ^1.60.0 and pin full Chromium for extension loading#1565
stevenbarragan wants to merge 1 commit into
garrytan:mainfrom
stevenbarragan:stevenbarragan/pin-chromium-launch-headed

Conversation

@stevenbarragan
Copy link
Copy Markdown

@stevenbarragan stevenbarragan commented May 17, 2026

Summary

Two related fixes for the headless browse daemon:

  • Playwright bump ^1.58.2^1.60.0: Chromium 1208 (bundled by 1.58.2, Chrome 145) fails Flutter Web's FlutterLoader environment compatibility check in headless mode, producing blank pages with webgl: false, no flt-glass-pane, and a pageerror: FlutterLoader could not find a build compatible with configuration and environment. Chromium 1223 (bundled by 1.60.0, Chrome 148) renders Flutter 3.41+ apps correctly in headless. Verified empirically against a Flutter 3.41.9 web build: same browser-manager.ts, same launch args, only the Chromium build differs.

  • launchHeaded() explicit executablePath pin: Playwright 1.49 changed chromium.launch({ headless: true }) to use chrome-headless-shell by default. chrome-headless-shell cannot load Chrome extensions — /open-gstack-browser and /pair-agent depend on the gstack sidebar extension. The headed path (launchPersistentContext({ headless: false })) was unaffected, but we relied on that implicitly. This patch pins executablePath: GSTACK_CHROMIUM_PATH || chromium.executablePath() explicitly so future Playwright changes to launchPersistentContext defaults can't silently break extension loading.

Boundaries respected:

  • GSTACK_CHROMIUM_PATH override still takes priority in both paths
  • No changes to CDP allowlist, stealth args, or any non-Playwright code
  • chrome-headless-shell remains the default for headless $B launches (Playwright 1.49+ behavior, unchanged)

Test plan

  • bun test browse/test/browser-manager-unit.test.ts browse/test/browser-manager-custom-chromium.test.ts — 10/10 pass
  • Full free test suite (bun test browse/test/ test/ make-pdf/test/ --ignore ...) — exit code 0
  • $B goto https://example.com round-trips correctly
  • Flutter 3.41.9 web app: blank page with webgl: false on 1.58.2 → full render with webgl: true, glass: 1, semantics: 10 on 1.60.0

🤖 Generated with Claude Code

@stevenbarragan stevenbarragan changed the title fix(browse): pin full Chromium executablePath in launchHeaded() for Playwright 1.49+ safety fix(browse): bump Playwright to ^1.60.0 for Flutter Web rendering + pin launchHeaded() executable May 17, 2026
…ension loading

Two related fixes:

1. Playwright bump ^1.58.2 → ^1.60.0 (Chromium 1208/Chrome 145 → 1223/Chrome 148).
   Chromium 1208 fails Flutter Web's FlutterLoader environment compatibility check
   in headless mode, producing blank pages with webgl:false and no flt-glass-pane.
   Chromium 1223 (1.60.0) renders Flutter 3.41+ apps correctly in headless.
   Verified empirically: same browse source, same args, only Chromium build differs.

2. launchHeaded() now explicitly passes executablePath: executablePath ||
   chromium.executablePath() to launchPersistentContext. Playwright 1.49 changed
   headless:true to use chrome-headless-shell (which cannot load extensions).
   The headed path was unaffected, but we were relying on that implicitly. This
   pin ensures /open-gstack-browser and /pair-agent keep loading the sidebar
   extension if Playwright ever changes launchPersistentContext defaults.

GSTACK_CHROMIUM_PATH still takes priority in both paths.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@stevenbarragan stevenbarragan force-pushed the stevenbarragan/pin-chromium-launch-headed branch from d9286e8 to ecf7efb Compare May 17, 2026 17:00
@stevenbarragan stevenbarragan changed the title fix(browse): bump Playwright to ^1.60.0 for Flutter Web rendering + pin launchHeaded() executable fix(browse): bump Playwright to ^1.60.0 and pin full Chromium for extension loading May 17, 2026
@jzeng151
Copy link
Copy Markdown

Heads up — this bump also fixes a more severe issue not mentioned in the PR description: playwright install chromium hangs
indefinitely during extraction on Node 26+ with Playwright ≤ 1.59.x, which fully blocks ./setup for new users on those Node
versions. I hit it twice in a row today (Node v26.1.0, gstack@HEAD): zip downloads fine (167MB), then extraction stalls at
~18MB with all worker threads parked in futex_wait/do_epoll_wait and zero CPU growth.

Root cause is fd-slicer's stream _destroy lifecycle, which never emits close on Node 26 — see
microsoft/playwright#40724. The fix vendors patched yauzl 3.2.1
(microsoft/playwright#40747, merged 2026-05-09) and first ships in
Playwright v1.60.0 — exactly what this PR pulls in. Confirmed locally that bumping to ^1.60.0 lets bunx playwright install chromium complete normally.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants