From 709d61a1918c494ec873cabd715c693cfc897195 Mon Sep 17 00:00:00 2001 From: Vlada Dusek Date: Tue, 19 May 2026 10:39:01 +0200 Subject: [PATCH 1/4] fix: Pin playwright to base image version in `uv` Dockerfile template MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The uv branch previously kept whatever playwright version happened to be in the env after `uv sync`, which can drift from the version baked into the Apify base image — so the actor would look for a Chromium build that `/pw-browsers/` doesn't ship. Snapshot the base image's playwright version before `COPY`/`uv sync` and pin to it afterwards (mirroring the existing sed-rewrite the pip and poetry branches use). --- .../{{cookiecutter.project_name}}/Dockerfile | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/crawlee/project_template/{{cookiecutter.project_name}}/Dockerfile b/src/crawlee/project_template/{{cookiecutter.project_name}}/Dockerfile index 4f958871e2..79ef82732f 100644 --- a/src/crawlee/project_template/{{cookiecutter.project_name}}/Dockerfile +++ b/src/crawlee/project_template/{{cookiecutter.project_name}}/Dockerfile @@ -41,8 +41,11 @@ RUN echo "Python version:" \ && echo "All installed Python packages:" \ && pip freeze # % elif cookiecutter.package_manager == 'uv' +# Snapshot the base image's playwright version before COPY/uv sync so we can pin to it later +# and stay aligned with the browser binaries baked into /pw-browsers. RUN pip install -U pip setuptools \ - && pip install 'uv<1' + && pip install 'uv<1' \ + && (hash playwright 2>/dev/null && playwright --version | cut -d ' ' -f 2 > /tmp/.base-playwright-version || true) ENV UV_PROJECT_ENVIRONMENT="/usr/local" @@ -51,15 +54,20 @@ COPY pyproject.toml uv.lock ./ RUN echo "Python version:" \ && python --version \ && echo "Installing dependencies:" \ - # Check if playwright is already installed - && PLAYWRIGHT_INSTALLED=$(pip freeze | grep -q playwright && echo "true" || echo "false") \ - && if [ "$PLAYWRIGHT_INSTALLED" = "true" ]; then \ - echo "Playwright already installed, excluding from uv sync" \ - && uv sync --frozen --no-install-project --no-editable -q --no-dev --inexact --no-install-package playwright; \ + && PLAYWRIGHT_BASE_VERSION=$(cat /tmp/.base-playwright-version 2>/dev/null || echo "") \ + && if [ -n "$PLAYWRIGHT_BASE_VERSION" ]; then \ + echo "Playwright $PLAYWRIGHT_BASE_VERSION pre-installed in base image; excluding from uv sync" \ + && uv sync --frozen --no-install-project --no-editable -q --no-dev --inexact --no-install-package playwright \ + && CURRENT_PLAYWRIGHT_VERSION=$(playwright --version 2>/dev/null | cut -d ' ' -f 2) \ + && if [ "$CURRENT_PLAYWRIGHT_VERSION" != "$PLAYWRIGHT_BASE_VERSION" ]; then \ + echo "Pinning playwright back to $PLAYWRIGHT_BASE_VERSION (was $CURRENT_PLAYWRIGHT_VERSION) to match shipped browsers" \ + && uv pip install --reinstall --no-deps "playwright==$PLAYWRIGHT_BASE_VERSION"; \ + fi; \ else \ - echo "Playwright not found, installing all dependencies" \ + echo "Playwright not found in base image, installing all dependencies as resolved in the lockfile" \ && uv sync --frozen --no-install-project --no-editable -q --no-dev --inexact; \ fi \ + && rm -f /tmp/.base-playwright-version \ && echo "All installed Python packages:" \ && pip freeze # % elif cookiecutter.package_manager == 'pip' From 7fbb85f65bb38b618343acf0b77089e2c1e7d7a2 Mon Sep 17 00:00:00 2001 From: Vlada Dusek Date: Mon, 25 May 2026 14:52:19 +0200 Subject: [PATCH 2/4] refactor: Simplify uv playwright pinning to single reinstall step Drop `--no-install-package playwright` and the post-sync version check; always reinstall `playwright==` after `uv sync` when a snapshot exists. Removes the asymmetry between the two mechanisms that guarded the same invariant from different angles, in response to PR review feedback. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../{{cookiecutter.project_name}}/Dockerfile | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/src/crawlee/project_template/{{cookiecutter.project_name}}/Dockerfile b/src/crawlee/project_template/{{cookiecutter.project_name}}/Dockerfile index 79ef82732f..a79bf61c5a 100644 --- a/src/crawlee/project_template/{{cookiecutter.project_name}}/Dockerfile +++ b/src/crawlee/project_template/{{cookiecutter.project_name}}/Dockerfile @@ -54,18 +54,11 @@ COPY pyproject.toml uv.lock ./ RUN echo "Python version:" \ && python --version \ && echo "Installing dependencies:" \ + && uv sync --frozen --no-install-project --no-editable -q --no-dev --inexact \ && PLAYWRIGHT_BASE_VERSION=$(cat /tmp/.base-playwright-version 2>/dev/null || echo "") \ && if [ -n "$PLAYWRIGHT_BASE_VERSION" ]; then \ - echo "Playwright $PLAYWRIGHT_BASE_VERSION pre-installed in base image; excluding from uv sync" \ - && uv sync --frozen --no-install-project --no-editable -q --no-dev --inexact --no-install-package playwright \ - && CURRENT_PLAYWRIGHT_VERSION=$(playwright --version 2>/dev/null | cut -d ' ' -f 2) \ - && if [ "$CURRENT_PLAYWRIGHT_VERSION" != "$PLAYWRIGHT_BASE_VERSION" ]; then \ - echo "Pinning playwright back to $PLAYWRIGHT_BASE_VERSION (was $CURRENT_PLAYWRIGHT_VERSION) to match shipped browsers" \ - && uv pip install --reinstall --no-deps "playwright==$PLAYWRIGHT_BASE_VERSION"; \ - fi; \ - else \ - echo "Playwright not found in base image, installing all dependencies as resolved in the lockfile" \ - && uv sync --frozen --no-install-project --no-editable -q --no-dev --inexact; \ + echo "Pinning playwright to $PLAYWRIGHT_BASE_VERSION to match the browser binaries shipped in the base image" \ + && uv pip install --reinstall --no-deps "playwright==$PLAYWRIGHT_BASE_VERSION"; \ fi \ && rm -f /tmp/.base-playwright-version \ && echo "All installed Python packages:" \ From bd01ec134e9dd939fb487474e441e90549c5d471 Mon Sep 17 00:00:00 2001 From: Vlada Dusek Date: Mon, 25 May 2026 14:57:13 +0200 Subject: [PATCH 3/4] use full option name in scripts --- .../project_template/{{cookiecutter.project_name}}/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/crawlee/project_template/{{cookiecutter.project_name}}/Dockerfile b/src/crawlee/project_template/{{cookiecutter.project_name}}/Dockerfile index a79bf61c5a..6ef9c4fa0f 100644 --- a/src/crawlee/project_template/{{cookiecutter.project_name}}/Dockerfile +++ b/src/crawlee/project_template/{{cookiecutter.project_name}}/Dockerfile @@ -54,7 +54,7 @@ COPY pyproject.toml uv.lock ./ RUN echo "Python version:" \ && python --version \ && echo "Installing dependencies:" \ - && uv sync --frozen --no-install-project --no-editable -q --no-dev --inexact \ + && uv sync --frozen --no-install-project --no-editable --quiet --no-dev --inexact \ && PLAYWRIGHT_BASE_VERSION=$(cat /tmp/.base-playwright-version 2>/dev/null || echo "") \ && if [ -n "$PLAYWRIGHT_BASE_VERSION" ]; then \ echo "Pinning playwright to $PLAYWRIGHT_BASE_VERSION to match the browser binaries shipped in the base image" \ From 0549486bfb7020d5d64b1fa93f45437cc08c457a Mon Sep 17 00:00:00 2001 From: Vlada Dusek Date: Tue, 26 May 2026 08:44:32 +0200 Subject: [PATCH 4/4] address feedback --- .../{{cookiecutter.project_name}}/Dockerfile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/crawlee/project_template/{{cookiecutter.project_name}}/Dockerfile b/src/crawlee/project_template/{{cookiecutter.project_name}}/Dockerfile index 6ef9c4fa0f..fff5c30993 100644 --- a/src/crawlee/project_template/{{cookiecutter.project_name}}/Dockerfile +++ b/src/crawlee/project_template/{{cookiecutter.project_name}}/Dockerfile @@ -41,11 +41,11 @@ RUN echo "Python version:" \ && echo "All installed Python packages:" \ && pip freeze # % elif cookiecutter.package_manager == 'uv' -# Snapshot the base image's playwright version before COPY/uv sync so we can pin to it later +COPY --from=ghcr.io/astral-sh/uv:0.11 /uv /uvx /bin/ + +# Snapshot the base image's playwright version before uv sync so we can pin to it later # and stay aligned with the browser binaries baked into /pw-browsers. -RUN pip install -U pip setuptools \ - && pip install 'uv<1' \ - && (hash playwright 2>/dev/null && playwright --version | cut -d ' ' -f 2 > /tmp/.base-playwright-version || true) +RUN hash playwright 2>/dev/null && playwright --version | cut -d ' ' -f 2 > /tmp/.base-playwright-version || true ENV UV_PROJECT_ENVIRONMENT="/usr/local"