From 5bf8081aecdaa11fd9a4fa413656271419cf0848 Mon Sep 17 00:00:00 2001 From: Pratyush Sharma <56130065+pratyush618@users.noreply.github.com> Date: Wed, 15 Jul 2026 18:31:36 +0530 Subject: [PATCH] Fix server launch on Playwright 1.60 Playwright 1.60 bundled its internals and removed the private lib/browserServerImpl.js that launchServer.js required, so `python -m camoufox server` died with MODULE_NOT_FOUND. Load the driver's package entrypoint instead, which is a bundled playwright-core and exposes launchServer as public API. The driver path is now passed explicitly rather than inferred from process.cwd(). Fixes #656 --- pythonlib/camoufox/launchServer.js | 25 ++++++++++++++++++------- pythonlib/camoufox/server.py | 6 +++++- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/pythonlib/camoufox/launchServer.js b/pythonlib/camoufox/launchServer.js index ea56e79..1e03cd8 100644 --- a/pythonlib/camoufox/launchServer.js +++ b/pythonlib/camoufox/launchServer.js @@ -1,7 +1,21 @@ -// Workaround that accesses Playwright's undocumented `launchServer` method in Python -// Without having to use the Node.js Playwright library. +// Workaround that accesses Playwright's `launchServer` method in Python +// Without having to install the Node.js Playwright library. -const { BrowserServerLauncherImpl } = require(`${process.cwd()}/lib/browserServerImpl.js`) +const path = require('path') + +// The driver shipped with playwright-python is a copy of playwright-core, so its +// entrypoint exposes `launchServer`. Resolve through the entrypoint rather than lib/ +// internals, whose layout is private and changes between releases: 1.60 bundled +// lib/browserServerImpl.js away, which broke this script. +const driverPackage = process.argv[2] + +let playwright +try { + playwright = require(path.join(driverPackage, 'index.js')) +} catch (error) { + console.error(`Error loading the Playwright driver from ${driverPackage}:`, error.message) + process.exit(1) +} function collectData() { return new Promise((resolve) => { @@ -22,10 +36,7 @@ collectData().then((options) => { console.time('Server launched'); console.info('Launching server...'); - const server = new BrowserServerLauncherImpl('firefox') - - // Call Playwright's `launchServer` method - server.launchServer(options).then(browserServer => { + playwright.firefox.launchServer(options).then(browserServer => { console.timeEnd('Server launched'); console.log('Websocket endpoint:\x1b[93m', browserServer.wsEndpoint(), '\x1b[0m'); // Continue forever diff --git a/pythonlib/camoufox/server.py b/pythonlib/camoufox/server.py index 1103aac..0f9b856 100644 --- a/pythonlib/camoufox/server.py +++ b/pythonlib/camoufox/server.py @@ -50,12 +50,16 @@ def launch_server(**kwargs) -> NoReturn: data = orjson.dumps(to_camel_case_dict(config)) + # The Playwright driver's package directory, which bundles playwright-core. + driver_package = Path(nodejs).parent / "package" + process = subprocess.Popen( # nosec [ nodejs, str(LAUNCH_SCRIPT), + str(driver_package), ], - cwd=Path(nodejs).parent / "package", + cwd=driver_package, stdin=subprocess.PIPE, text=True, )