guix_mirror_bot pushed a commit to branch master
in repository guix.
commit 29a4d07db97737e1e53ddf62c69d4abbe896ba9f
Author: Danny Milosavljevic <[email protected]>
AuthorDate: Fri Jan 2 23:54:25 2026 +0100
gnu: Add node-playwright-core.
* gnu/packages/playwright.scm: New file.
(node-playwright-core): New variable.
* gnu/local.mk (GNU_SYSTEM_MODULES): Add reference to file.
Change-Id: Ie94128a2bbbd0fadbd8762dc99b802706aee3530
---
gnu/local.mk | 1 +
gnu/packages/playwright.scm | 257 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 258 insertions(+)
diff --git a/gnu/local.mk b/gnu/local.mk
index e619ab688c..f114e326e5 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -553,6 +553,7 @@ GNU_SYSTEM_MODULES = \
%D%/packages/diagram.scm \
%D%/packages/pkg-config.scm \
%D%/packages/plan9.scm \
+ %D%/packages/playwright.scm \
%D%/packages/plotutils.scm \
%D%/packages/poedit.scm \
%D%/packages/polkit.scm \
diff --git a/gnu/packages/playwright.scm b/gnu/packages/playwright.scm
new file mode 100644
index 0000000000..c492674ae8
--- /dev/null
+++ b/gnu/packages/playwright.scm
@@ -0,0 +1,257 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2025 Danny Milosavljevic <[email protected]>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (gnu packages playwright)
+ #:use-module ((guix licenses) #:prefix license:)
+ #:use-module (guix packages)
+ #:use-module (guix gexp)
+ #:use-module (guix git-download)
+ #:use-module (guix build-system node)
+ #:use-module (guix utils)
+ #:use-module (gnu packages)
+ #:use-module (gnu packages chromium)
+ #:use-module (gnu packages node)
+ #:use-module (gnu packages node-xyz)
+ #:use-module (gnu packages python)
+ #:use-module (gnu packages web))
+
+;; Playwright is a browser automation framework. Upstream provides patched
+;; versions of Firefox and WebKit browsers, but those require building
+;; custom browser forks. This package only supports Chromium-based browsers
+;; (using the system ungoogled-chromium) since Chromium's DevTools Protocol
+;; is sufficient for automation without patches.
+;;
+;; Firefox support would require Playwright's "Juggler" protocol patches.
+;; WebKit support would require Playwright's WebKit automation patches.
+;; Both are invasive changes to browser source code.
+;;
+;; In the future, WebDriver BiDi (a W3C standard) may allow Playwright to
+;; work with unpatched browsers.
+
+(define-public node-playwright-core
+ (package
+ (name "node-playwright-core")
+ (version "1.50.0")
+ (source
+ (origin
+ (method git-fetch)
+ (uri (git-reference
+ (url "https://github.com/microsoft/playwright")
+ (commit (string-append "v" version))))
+ (file-name (git-file-name name version))
+ (sha256
+ (base32 "0xymivpn2c4srbaqdix3qx2zcr6cx5zgs2a20drvi4dmkspn4jz6"))
+ (modules '((guix build utils)))
+ (snippet
+ '(delete-file-recursively "packages/playwright-core/bundles"))))
+ (build-system node-build-system)
+ (arguments
+ (list
+ #:tests? #f ; Tests require browser binaries.
+ #:phases
+ #~(modify-phases %standard-phases
+ (add-after 'unpack 'break-monorepo-structure
+ (lambda _
+ ;; This is a monorepo with npm workspaces. Delete root
package.json
+ ;; and lock files to prevent npm from reading workspace config.
+ (delete-file "package.json")
+ (for-each delete-file
+ (find-files "." "package-lock\\.json$"))))
+ (add-after 'break-monorepo-structure 'change-to-package-directory
+ (lambda _
+ (chdir "packages/playwright-core")))
+ (add-after 'unpack 'skip-browser-download
+ (lambda _
+ (setenv "PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD" "1")))
+ (add-after 'unpack 'unbundle-dependencies
+ (lambda _
+ (substitute* "packages/playwright-core/src/zipBundle.ts"
+ (("require\\('./zipBundleImpl'\\)\\.yazl")
+ "require('yazl')")
+ (("require\\('./zipBundleImpl'\\)\\.yauzl")
+ "require('yauzl')")
+ (("require\\('./zipBundleImpl'\\)\\.extract")
+ "require('extract-zip')"))
+ (substitute* "packages/playwright-core/src/utilsBundle.ts"
+ (("require\\('./utilsBundleImpl'\\)\\.colors")
+ "require('colors/safe')")
+ (("require\\('./utilsBundleImpl'\\)\\.debug")
+ "require('debug')")
+ (("require\\('./utilsBundleImpl'\\)\\.diff")
+ "require('diff')")
+ (("require\\('./utilsBundleImpl'\\)\\.dotenv")
+ "require('dotenv')")
+ (("require\\('./utilsBundleImpl'\\)\\.getProxyForUrl")
+ "require('proxy-from-env').getProxyForUrl")
+ (("require\\('./utilsBundleImpl'\\)\\.HttpsProxyAgent")
+ "require('https-proxy-agent').HttpsProxyAgent")
+ (("require\\('./utilsBundleImpl'\\)\\.jpegjs")
+ "require('jpeg-js')")
+ (("require\\('./utilsBundleImpl'\\)\\.lockfile")
+ "require('proper-lockfile')")
+ (("require\\('./utilsBundleImpl'\\)\\.mime")
+ "require('mime')")
+ (("require\\('./utilsBundleImpl'\\)\\.minimatch")
+ "require('minimatch')")
+ (("require\\('./utilsBundleImpl'\\)\\.open")
+ "require('open')")
+ (("require\\('./utilsBundleImpl'\\)\\.PNG")
+ "require('pngjs').PNG")
+ (("require\\('./utilsBundleImpl'\\)\\.program")
+ "require('commander').program")
+ (("require\\('./utilsBundleImpl'\\)\\.progress")
+ "require('progress')")
+ (("require\\('./utilsBundleImpl'\\)\\.SocksProxyAgent")
+ "require('socks-proxy-agent').SocksProxyAgent")
+ (("require\\('./utilsBundleImpl'\\)\\.yaml")
+ "require('yaml')")
+ (("require\\('./utilsBundleImpl'\\)\\.wsServer")
+ "require('ws').WebSocketServer")
+ (("require\\('./utilsBundleImpl'\\)\\.wsReceiver")
+ "require('ws').Receiver")
+ (("require\\('./utilsBundleImpl'\\)\\.wsSender")
+ "require('ws').Sender")
+ (("require\\('./utilsBundleImpl'\\)\\.ws\\b")
+ "require('ws')")
+ (("require\\('./utilsBundleImpl'\\)\\.StackUtils")
+ "require('stack-utils')"))))
+ (add-after 'unbundle-dependencies 'add-unbundled-dependencies
+ (lambda _
+ ;; Add dependencies that were unbundled from
utilsBundle/zipBundle.
+ ;; Must run before patch-dependencies which minifies
package.json.
+ (modify-json
+ #:file "packages/playwright-core/package.json"
+ (lambda (pkg)
+ (acons "dependencies"
+ '(("colors" . "*")
+ ("commander" . "*")
+ ("debug" . "*")
+ ("diff" . "*")
+ ("dotenv" . "*")
+ ("extract-zip" . "*")
+ ("https-proxy-agent" . "*")
+ ("jpeg-js" . "*")
+ ("mime" . "*")
+ ("minimatch" . "*")
+ ("open" . "*")
+ ("pngjs" . "*")
+ ("progress" . "*")
+ ("proper-lockfile" . "*")
+ ("proxy-from-env" . "*")
+ ("socks-proxy-agent" . "*")
+ ("stack-utils" . "*")
+ ("ws" . "*")
+ ("yaml" . "*")
+ ("yazl" . "*")
+ ("yauzl" . "*"))
+ pkg)))))
+ (add-before 'build 'generate-injected-scripts
+ (lambda _
+ ;; Run generate_injected.js to create src/generated/*.ts files.
+ (invoke "node" "../../utils/generate_injected.js")))
+ (add-after 'generate-injected-scripts 'add-build-script
+ (lambda _
+ ;; Upstream uses Babel, but Babel isn't packaged. Use esbuild.
+ ;; Compile TypeScript and copy non-TS files (JS, JSON, PNG).
+ (modify-json
+ (lambda (pkg)
+ (acons "scripts"
+ '(("build" . "find src -name '*.ts' | xargs esbuild
--outdir=lib --format=cjs --platform=node && cp -r src/third_party lib/ && find
src \\( -name '*.json' -o -name '*.png' \\) -exec sh -c 'mkdir -p lib/$(dirname
${0#src/}) && cp $0 lib/${0#src/}' {} \\;"))
+ pkg)))))
+ (add-before 'install 'set-cc
+ (lambda _
+ (setenv "CC" #$(cc-for-target))))
+ (add-after 'install 'wrap-playwright-cli
+ (lambda* (#:key inputs outputs #:allow-other-keys)
+ (let* ((out (assoc-ref outputs "out"))
+ (cli (string-append out
"/lib/node_modules/playwright-core/cli.js")))
+ (wrap-program cli
+ ;; Avoid vite dependency.
+ `("PW_CODEGEN_NO_INSPECTOR" = ("1"))
+ `("PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD" = ("1")))))))))
+ (inputs
+ (list node-esbuild
+ ;; Dependencies (unbundled from utilsBundle).
+ node-colors
+ node-commander
+ node-debug
+ node-diff
+ node-dotenv
+ node-graceful-fs
+ node-https-proxy-agent
+ node-jpeg-js
+ node-mime
+ node-minimatch-3
+ node-ms
+ node-open
+ node-pngjs
+ node-progress
+ node-proper-lockfile
+ node-proxy-from-env
+ node-retry
+ node-signal-exit
+ node-socks-proxy-agent
+ node-stack-utils
+ node-ws
+ node-yaml
+ ;; Dependencies (unbundled from zipBundle).
+ node-yazl
+ node-yauzl
+ node-extract-zip))
+ (native-inputs
+ (list esbuild python))
+ (native-search-paths
+ (list
+ (search-path-specification
+ (variable "PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH")
+ (file-type 'regular)
+ (separator #f) ;single entry
+ (files '("bin/chromium")))
+ (search-path-specification
+ (variable "PWTEST_CLI_EXECUTABLE_PATH")
+ (file-type 'regular)
+ (separator #f) ;single entry
+ (files '("bin/chromium")))))
+ (home-page "https://playwright.dev/")
+ (synopsis "Browser automation library (Chromium-only)")
+ (description
+ "Playwright is a framework for browser automation and end-to-end testing.
+This package provides @code{playwright-core}, the library without bundled
+browsers.
+
+@strong{Important}: This package only supports Chromium-based browsers.
+Firefox and WebKit are not supported because Playwright requires custom-patched
+versions of those browsers that are not packaged for Guix.
+
+To use Playwright with the system Chromium, either:
+@enumerate
+@item
+Set the environment variable @env{PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH} to the
+Chromium binary path, or
+@item
+Use the @code{executablePath} option in your Playwright code:
+@example
+const browser = await chromium.launch(@{
+ executablePath: '/run/current-system/profile/bin/chromium'
+@});
+@end example
+
+For the command line variant $code{playwright-core}, set the environment
+variable $env{PWTEST_CLI_EXECUTABLE_PATH} to the Chromium binary path.
+@end enumerate")
+ (license license:asl2.0)))