1
0
mirror of https://git.savannah.gnu.org/git/guix.git synced 2026-04-06 13:10:33 +02:00

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
This commit is contained in:
Danny Milosavljevic
2026-01-02 23:54:25 +01:00
parent 70d2a055b5
commit 29a4d07db9
2 changed files with 258 additions and 0 deletions

View File

@@ -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 \

257
gnu/packages/playwright.scm Normal file
View File

@@ -0,0 +1,257 @@
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2025 Danny Milosavljevic <dannym@friendly-machines.com>
;;;
;;; 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)))