From e8e4025d63650bc559fb813df4eb43f60575149d Mon Sep 17 00:00:00 2001 From: Yury Semikhatsky Date: Fri, 12 Jun 2026 10:27:50 -0700 Subject: [PATCH] feat: assemble driver from npm instead of CDN Download the driver from the canonical npm registry rather than cdn.playwright.dev. Each platform's driver is assembled from the playwright-core npm package plus the matching Node.js binary from nodejs.org, the same way the upstream Playwright build does it, mirroring the approach in playwright-dotnet#3322. The npm package does not contain api.json, so generate_api.sh now generates it from the upstream Playwright source at the exact commit that produced the driver version (resolved via npm gitHead), instead of relying on the bundled driver's print-api-json command. References https://github.com/microsoft/playwright-internal/issues/291 Co-Authored-By: Claude Opus 4.8 (1M context) --- CONTRIBUTING.md | 7 +-- scripts/download_driver.sh | 93 ++++++++++++++++++++++++++++---------- scripts/generate_api.sh | 53 ++++++++++++++-------- 3 files changed, 105 insertions(+), 48 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0fa9b18c0..cd67302b2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -20,12 +20,14 @@ git clone https://github.com/microsoft/playwright-java cd playwright-java ``` -2. Run the following script to download Playwright driver for all platforms into `driver-bundle/src/main/resources/driver/` directory (browser binaries for Chromium, Firefox and WebKit will be automatically downloaded later on first Playwright run). +2. Run the following script to download and assemble the Playwright driver for all platforms into `driver-bundle/src/main/resources/driver/` directory (browser binaries for Chromium, Firefox and WebKit will be automatically downloaded later on first Playwright run). ```bash scripts/download_driver.sh ``` +Each driver is assembled from the [`playwright-core`](https://www.npmjs.com/package/playwright-core) npm package (version pinned in [scripts/DRIVER_VERSION](scripts/DRIVER_VERSION)) and the matching Node.js binary from https://nodejs.org, the same way the upstream Playwright build does it. + ### Building and running the tests with Maven ```bash @@ -39,10 +41,9 @@ BROWSER=chromium mvn test -Dtest=TestPageNetworkSizes ### Generating API -Public Java API is generated from api.json which is produced by `print-api-json` command of playwright CLI. To regenerate Java interfaces for the current driver run the following commands: +Public Java API is generated from api.json, which is generated from the upstream Playwright source at the exact commit that produced the driver version in [scripts/DRIVER_VERSION](scripts/DRIVER_VERSION) (resolved via `npm view playwright@ gitHead`). `scripts/generate_api.sh` fetches a minimal upstream checkout automatically; set `PW_SRC_DIR` to reuse an existing `microsoft/playwright` checkout instead. To regenerate Java interfaces for the current driver run: ```bash -./scripts/download_driver.sh ./scripts/generate_api.sh ``` diff --git a/scripts/download_driver.sh b/scripts/download_driver.sh index eaa6aeebb..dba7f75d2 100755 --- a/scripts/download_driver.sh +++ b/scripts/download_driver.sh @@ -8,8 +8,10 @@ cd "$(dirname $0)" if [[ ($1 == '-h') || ($1 == '--help') ]]; then echo "" - echo "This script for downloading playwright driver for all platforms." - echo "The downloaded files will be put under 'driver-bundle/src/main/resources/driver'." + echo "This script downloads and assembles the Playwright driver for all platforms." + echo "Each driver is assembled from the 'playwright-core' npm package and the matching" + echo "Node.js binary from https://nodejs.org, the same way the upstream Playwright build" + echo "does it. The result is put under 'driver-bundle/src/main/resources/driver'." echo "" echo "Usage: scripts/download_driver.sh [option]" echo "" @@ -19,8 +21,40 @@ if [[ ($1 == '-h') || ($1 == '--help') ]]; then exit 0 fi +# Ubuntu 24.04-arm64 emulated via qemu has a bug, so we prefer wget over curl. +# See https://github.com/microsoft/playwright-java/issues/1678. +download() { + local url=$1 + local out=$2 + echo "Downloading $url" + if command -v wget &> /dev/null; then + wget -q -O "$out" "$url" + else + curl --retry 5 --retry-delay 2 -fL -o "$out" "$url" + fi +} + DRIVER_VERSION=$(head -1 ./DRIVER_VERSION) -FILE_PREFIX=playwright-$DRIVER_VERSION + +# Resolve the exact upstream commit that produced this driver version, so that the +# bundled Node.js version matches the driver exactly. +GIT_HEAD=$(npm view playwright@"$DRIVER_VERSION" gitHead) +if [[ -z "$GIT_HEAD" ]]; then + echo "Failed to resolve upstream commit (gitHead) for playwright@$DRIVER_VERSION" + exit 1 +fi + +# The Node.js version is kept in sync with the driver version in the upstream build script. +NODE_VERSION=$(curl -fsSL "https://raw.githubusercontent.com/microsoft/playwright/$GIT_HEAD/utils/build/build-playwright-driver.sh" \ + | sed -n 's/^NODE_VERSION="\([^"]*\)".*/\1/p') +if [[ -z "$NODE_VERSION" ]]; then + echo "Failed to determine Node.js version for playwright@$DRIVER_VERSION ($GIT_HEAD)" + exit 1 +fi + +echo "Driver version: $DRIVER_VERSION" +echo "Upstream commit: $GIT_HEAD" +echo "Node.js version: $NODE_VERSION" cd ../driver-bundle/src/main/resources @@ -32,32 +66,41 @@ fi mkdir -p driver cd driver -for PLATFORM in mac mac-arm64 linux linux-arm64 win32_x64 +# Download the platform-independent driver package (playwright-core) once. +CORE_TGZ="$(pwd)/playwright-core-$DRIVER_VERSION.tgz" +download "https://registry.npmjs.org/playwright-core/-/playwright-core-$DRIVER_VERSION.tgz" "$CORE_TGZ" + +# :: +for ENTRY in \ + "mac:darwin-x64:tar.gz" \ + "mac-arm64:darwin-arm64:tar.gz" \ + "linux:linux-x64:tar.gz" \ + "linux-arm64:linux-arm64:tar.gz" \ + "win32_x64:win-x64:zip" do - FILE_NAME=$FILE_PREFIX-$PLATFORM.zip - mkdir $PLATFORM - cd $PLATFORM - echo "Downloading driver for $PLATFORM to $(pwd)" - - URL=https://cdn.playwright.dev/builds/driver - if [[ "$DRIVER_VERSION" == *-alpha* || "$DRIVER_VERSION" == *-beta* || "$DRIVER_VERSION" == *-next* ]]; then - URL=$URL/next - fi - URL=$URL/$FILE_NAME - echo "Using url: $URL" - # Ubuntu 24.04-arm64 emulated via qemu has a bug, so we prefer wget over curl. - # See https://github.com/microsoft/playwright-java/issues/1678. - if command -v wget &> /dev/null; then - wget $URL + IFS=':' read -r PLATFORM NODE_SUFFIX ARCHIVE <<< "$ENTRY" + echo "Assembling driver for $PLATFORM to $(pwd)/$PLATFORM" + mkdir "$PLATFORM" + + # 1. playwright-core package contents -> $PLATFORM/package + tar -xzf "$CORE_TGZ" -C "$PLATFORM" + + # 2. Node.js binary and its license from the official Node.js distribution. + NODE_DIR="node-v$NODE_VERSION-$NODE_SUFFIX" + NODE_ARCHIVE="$NODE_DIR.$ARCHIVE" + download "https://nodejs.org/dist/v$NODE_VERSION/$NODE_DIR.$ARCHIVE" "$NODE_ARCHIVE" + if [[ $ARCHIVE == "zip" ]]; then + unzip -joq "$NODE_ARCHIVE" "$NODE_DIR/node.exe" -d "$PLATFORM" + unzip -joq "$NODE_ARCHIVE" "$NODE_DIR/LICENSE" -d "$PLATFORM" else - curl --retry 5 --retry-delay 2 -fL -O $URL + tar -xzf "$NODE_ARCHIVE" -C "$PLATFORM" --strip-components=2 "$NODE_DIR/bin/node" + tar -xzf "$NODE_ARCHIVE" -C "$PLATFORM" --strip-components=1 "$NODE_DIR/LICENSE" fi - unzip $FILE_NAME -d . - rm $FILE_NAME - - cd - + rm -f "$NODE_ARCHIVE" done +rm -f "$CORE_TGZ" + echo "" -echo "All drivers have been successfully downloaded." +echo "All drivers have been successfully assembled." echo "" diff --git a/scripts/generate_api.sh b/scripts/generate_api.sh index cc8c8c6c9..78ed6d4ad 100755 --- a/scripts/generate_api.sh +++ b/scripts/generate_api.sh @@ -6,26 +6,39 @@ set +x trap 'cd $(pwd -P)' EXIT cd "$(dirname "$0")/.." -PLAYWRIGHT_CLI="unknown" -case $(uname) in -Darwin) - PLAYWRIGHT_CLI=./driver-bundle/src/main/resources/driver/mac/package/cli.js - ;; -Linux) - PLAYWRIGHT_CLI=./driver-bundle/src/main/resources/driver/linux/package/cli.js - ;; -MINGW64*) - PLAYWRIGHT_CLI=./driver-bundle/src/main/resources/driver/win32_x64/package/cli.js - ;; -*) - echo "Unknown platform '$(uname)'" - exit 1; - ;; -esac - -echo "Updating api.json from $($PLAYWRIGHT_CLI --version)" - -node $PLAYWRIGHT_CLI print-api-json > ./tools/api-generator/src/main/resources/api.json +DRIVER_VERSION=$(head -1 ./scripts/DRIVER_VERSION) + +# api.json is generated from the upstream Playwright source at the exact commit +# that produced this driver version. Set PW_SRC_DIR to reuse an existing upstream +# checkout, otherwise a minimal one is fetched into a temporary directory. +GIT_HEAD=$(npm view playwright@"$DRIVER_VERSION" gitHead) +if [[ -z "$GIT_HEAD" ]]; then + echo "Failed to resolve upstream commit (gitHead) for playwright@$DRIVER_VERSION" + exit 1 +fi + +CLONED_UPSTREAM="" +if [[ -n "$PW_SRC_DIR" ]]; then + UPSTREAM_DIR="$PW_SRC_DIR" + echo "Using upstream Playwright checkout at $UPSTREAM_DIR (PW_SRC_DIR)" +else + UPSTREAM_DIR=$(mktemp -d) + CLONED_UPSTREAM="$UPSTREAM_DIR" + echo "Fetching upstream Playwright source at $GIT_HEAD" + # generateApiJson.js only needs utils/ and docs/, so fetch just those. + git clone --quiet --filter=blob:none --no-checkout https://github.com/microsoft/playwright.git "$UPSTREAM_DIR" + git -C "$UPSTREAM_DIR" sparse-checkout init --cone + git -C "$UPSTREAM_DIR" sparse-checkout set utils docs + git -C "$UPSTREAM_DIR" checkout --quiet "$GIT_HEAD" +fi + +echo "Updating api.json from upstream playwright@$DRIVER_VERSION ($GIT_HEAD)" +API_JSON_MODE=1 node "$UPSTREAM_DIR/utils/doclint/generateApiJson.js" \ + > ./tools/api-generator/src/main/resources/api.json + +if [[ -n "$CLONED_UPSTREAM" ]]; then + rm -rf "$CLONED_UPSTREAM" +fi mvn compile -f ./tools/api-generator --no-transfer-progress