playwright-ci-caching
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseCaching Playwright Browsers in CI/CD
在CI/CD中缓存Playwright浏览器
When to Use This Skill
何时使用该技巧
Use this skill when:
- Setting up CI/CD for a project with Playwright E2E tests
- Build times are slow due to browser downloads (~400MB, 1-2 minutes)
- You want automatic cache invalidation when Playwright version changes
- Using GitHub Actions or Azure DevOps pipelines
在以下场景使用该技巧:
- 为包含Playwright E2E测试的项目搭建CI/CD流水线
- 浏览器下载导致构建速度缓慢(约400MB,耗时1-2分钟)
- 希望在Playwright版本变更时自动失效缓存
- 使用GitHub Actions或Azure DevOps流水线
The Problem
问题背景
Playwright browsers (~400MB) must be downloaded on every CI run by default. This:
- Adds 1-2 minutes to every build
- Wastes bandwidth
- Can fail on transient network issues
- Slows down PR feedback loops
默认情况下,每次CI运行都必须下载Playwright浏览器(约400MB),这会:
- 为每次构建增加1-2分钟的耗时
- 浪费带宽
- 可能因临时网络问题导致构建失败
- 拉慢PR反馈周期
Core Pattern
核心实现模式
- Extract Playwright version from (CPM) to use as cache key
Directory.Packages.props - Cache browser binaries using platform-appropriate paths
- Conditional install - only download on cache miss
- Automatic cache bust - key includes version, so package upgrades invalidate cache
- 提取Playwright版本:从(CPM)中提取版本号作为缓存键
Directory.Packages.props - 缓存浏览器二进制文件:使用对应平台的路径进行缓存
- 条件性安装:仅在缓存未命中时才下载浏览器
- 自动缓存失效:缓存键包含版本号,因此升级包版本会自动使缓存失效
Cache Paths by OS
各操作系统对应的缓存路径
| OS | Path |
|---|---|
| Linux | |
| macOS | |
| Windows | |
| 操作系统 | 路径 |
|---|---|
| Linux | |
| macOS | |
| Windows | |
GitHub Actions
GitHub Actions配置
yaml
- name: Get Playwright Version
shell: pwsh
run: |
$propsPath = "Directory.Packages.props"
[xml]$props = Get-Content $propsPath
$version = $props.Project.ItemGroup.PackageVersion |
Where-Object { $_.Include -eq "Microsoft.Playwright" } |
Select-Object -ExpandProperty Version
echo "PlaywrightVersion=$version" >> $env:GITHUB_ENV
- name: Cache Playwright Browsers
id: playwright-cache
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-${{ env.PlaywrightVersion }}
- name: Install Playwright Browsers
if: steps.playwright-cache.outputs.cache-hit != 'true'
shell: pwsh
run: ./build/playwright.ps1 install --with-depsyaml
- name: Get Playwright Version
shell: pwsh
run: |
$propsPath = "Directory.Packages.props"
[xml]$props = Get-Content $propsPath
$version = $props.Project.ItemGroup.PackageVersion |
Where-Object { $_.Include -eq "Microsoft.Playwright" } |
Select-Object -ExpandProperty Version
echo "PlaywrightVersion=$version" >> $env:GITHUB_ENV
- name: Cache Playwright Browsers
id: playwright-cache
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-${{ env.PlaywrightVersion }}
- name: Install Playwright Browsers
if: steps.playwright-cache.outputs.cache-hit != 'true'
shell: pwsh
run: ./build/playwright.ps1 install --with-depsMulti-OS GitHub Actions
多操作系统的GitHub Actions配置
For workflows that run on multiple operating systems:
yaml
- name: Cache Playwright Browsers
id: playwright-cache
uses: actions/cache@v4
with:
path: |
~/.cache/ms-playwright
~/Library/Caches/ms-playwright
~/AppData/Local/ms-playwright
key: ${{ runner.os }}-playwright-${{ env.PlaywrightVersion }}针对在多操作系统上运行的工作流:
yaml
- name: Cache Playwright Browsers
id: playwright-cache
uses: actions/cache@v4
with:
path: |
~/.cache/ms-playwright
~/Library/Caches/ms-playwright
~/AppData/Local/ms-playwright
key: ${{ runner.os }}-playwright-${{ env.PlaywrightVersion }}Azure DevOps
Azure DevOps配置
yaml
- task: PowerShell@2
displayName: 'Get Playwright Version'
inputs:
targetType: 'inline'
script: |
[xml]$props = Get-Content "Directory.Packages.props"
$version = $props.Project.ItemGroup.PackageVersion |
Where-Object { $_.Include -eq "Microsoft.Playwright" } |
Select-Object -ExpandProperty Version
Write-Host "##vso[task.setvariable variable=PlaywrightVersion]$version"
- task: Cache@2
displayName: 'Cache Playwright Browsers'
inputs:
key: 'playwright | "$(Agent.OS)" | $(PlaywrightVersion)'
path: '$(HOME)/.cache/ms-playwright'
cacheHitVar: 'PlaywrightCacheHit'
- task: PowerShell@2
displayName: 'Install Playwright Browsers'
condition: ne(variables['PlaywrightCacheHit'], 'true')
inputs:
filePath: 'build/playwright.ps1'
arguments: 'install --with-deps'yaml
- task: PowerShell@2
displayName: 'Get Playwright Version'
inputs:
targetType: 'inline'
script: |
[xml]$props = Get-Content "Directory.Packages.props"
$version = $props.Project.ItemGroup.PackageVersion |
Where-Object { $_.Include -eq "Microsoft.Playwright" } |
Select-Object -ExpandProperty Version
Write-Host "##vso[task.setvariable variable=PlaywrightVersion]$version"
- task: Cache@2
displayName: 'Cache Playwright Browsers'
inputs:
key: 'playwright | "$(Agent.OS)" | $(PlaywrightVersion)'
path: '$(HOME)/.cache/ms-playwright'
cacheHitVar: 'PlaywrightCacheHit'
- task: PowerShell@2
displayName: 'Install Playwright Browsers'
condition: ne(variables['PlaywrightCacheHit'], 'true')
inputs:
filePath: 'build/playwright.ps1'
arguments: 'install --with-deps'Helper Script: playwright.ps1
辅助脚本:playwright.ps1
Create a script that discovers and runs the Playwright CLI. This abstracts away the Playwright CLI location which varies by project structure.
build/playwright.ps1powershell
undefined创建脚本,用于查找并运行Playwright CLI。该脚本可抽象Playwright CLI的位置(不同项目结构中位置可能不同)。
build/playwright.ps1powershell
undefinedbuild/playwright.ps1
build/playwright.ps1
Discovers Microsoft.Playwright.dll and runs the bundled Playwright CLI
查找Microsoft.Playwright.dll并运行捆绑的Playwright CLI
param(
[Parameter(ValueFromRemainingArguments = $true)]
[string[]]$Arguments
)
param(
[Parameter(ValueFromRemainingArguments = $true)]
[string[]]$Arguments
)
Find the Playwright DLL (after dotnet build/restore)
查找Playwright DLL(需先执行dotnet build/restore)
$playwrightDll = Get-ChildItem -Path . -Recurse -Filter "Microsoft.Playwright.dll" -ErrorAction SilentlyContinue |
Select-Object -First 1
if (-not $playwrightDll) {
Write-Error "Microsoft.Playwright.dll not found. Run 'dotnet build' first."
exit 1
}
$playwrightDir = $playwrightDll.DirectoryName
$playwrightDll = Get-ChildItem -Path . -Recurse -Filter "Microsoft.Playwright.dll" -ErrorAction SilentlyContinue |
Select-Object -First 1
if (-not $playwrightDll) {
Write-Error "未找到Microsoft.Playwright.dll,请先执行'dotnet build'。"
exit 1
}
$playwrightDir = $playwrightDll.DirectoryName
Find the playwright CLI (path varies by OS and node version)
查找playwright CLI(路径因操作系统和node版本而异)
$playwrightCmd = Get-ChildItem -Path "$playwrightDir/.playwright/node" -Recurse -Filter "playwright.cmd" -ErrorAction SilentlyContinue |
Select-Object -First 1
if (-not $playwrightCmd) {
# Try Unix executable
$playwrightCmd = Get-ChildItem -Path "$playwrightDir/.playwright/node" -Recurse -Filter "playwright" -ErrorAction SilentlyContinue |
Where-Object { $_.Name -eq "playwright" } |
Select-Object -First 1
}
if (-not $playwrightCmd) {
Write-Error "Playwright CLI not found in $playwrightDir/.playwright/node"
exit 1
}
Write-Host "Using Playwright CLI: $($playwrightCmd.FullName)"
& $playwrightCmd.FullName @Arguments
Usage:
```bash$playwrightCmd = Get-ChildItem -Path "$playwrightDir/.playwright/node" -Recurse -Filter "playwright.cmd" -ErrorAction SilentlyContinue |
Select-Object -First 1
if (-not $playwrightCmd) {
# 尝试查找Unix可执行文件
$playwrightCmd = Get-ChildItem -Path "$playwrightDir/.playwright/node" -Recurse -Filter "playwright" -ErrorAction SilentlyContinue |
Where-Object { $_.Name -eq "playwright" } |
Select-Object -First 1
}
if (-not $playwrightCmd) {
Write-Error "在$playwrightDir/.playwright/node中未找到Playwright CLI"
exit 1
}
Write-Host "使用Playwright CLI:$($playwrightCmd.FullName)"
& $playwrightCmd.FullName @Arguments
使用方法:
```bashInstall browsers
安装浏览器
./build/playwright.ps1 install --with-deps
./build/playwright.ps1 install --with-deps
Install specific browser
安装特定浏览器
./build/playwright.ps1 install chromium
./build/playwright.ps1 install chromium
Show installed browsers
查看已安装的浏览器
./build/playwright.ps1 install --dry-run
undefined./build/playwright.ps1 install --dry-run
undefinedPrerequisites
前提条件
This pattern assumes:
-
Central Package Management (CPM) with:
Directory.Packages.propsxml<Project> <ItemGroup> <PackageVersion Include="Microsoft.Playwright" Version="1.40.0" /> </ItemGroup> </Project> -
Project has been built before running(so DLLs exist)
playwright.ps1 -
PowerShell available on CI agents (pre-installed on GitHub Actions and Azure DevOps)
该实现模式基于以下假设:
-
**使用中央包管理(CPM)**并包含:
Directory.Packages.propsxml<Project> <ItemGroup> <PackageVersion Include="Microsoft.Playwright" Version="1.40.0" /> </ItemGroup> </Project> -
运行前已构建项目(确保DLL文件存在)
playwright.ps1 -
CI代理上已安装PowerShell(GitHub Actions和Azure DevOps默认已安装)
Why Version-Based Cache Keys Matter
基于版本的缓存键为何重要
Using the Playwright version in the cache key ensures:
- Automatic invalidation when you upgrade Playwright
- No stale browser binaries that don't match the SDK version
- No manual cache clearing needed after version bumps
If you hardcode the cache key (e.g., ), you'll need to manually bump it every time you upgrade Playwright, or you'll get cryptic version mismatch errors.
playwright-browsers-v1在缓存键中使用Playwright版本可确保:
- 自动失效:升级Playwright版本时自动失效缓存
- 无过期浏览器二进制文件:避免缓存的浏览器与SDK版本不匹配
- 版本升级后无需手动清理缓存
如果硬编码缓存键(例如),则每次升级Playwright时都需要手动更新缓存键,否则会出现版本不匹配的模糊错误。
playwright-browsers-v1Troubleshooting
故障排除
Cache not being used
缓存未被使用
- Verify the version extraction step outputs the correct version
- Check that the cache path matches your OS
- Ensure exists and has the Playwright package
Directory.Packages.props
- 验证版本提取步骤是否输出了正确的版本号
- 检查缓存路径是否与当前操作系统匹配
- 确保存在且包含Playwright包
Directory.Packages.props
"Browser not found" after cache hit
缓存命中后提示“浏览器未找到”
The cached browsers don't match the Playwright SDK version. This happens when:
- The cache key doesn't include the version
- The version extraction failed silently
Fix: Ensure the Playwright version is in the cache key.
缓存的浏览器与Playwright SDK版本不匹配,通常由以下原因导致:
- 缓存键未包含版本号
- 版本提取步骤静默失败
解决方法:确保缓存键中包含Playwright版本号。
playwright.ps1 can't find the DLL
playwright.ps1无法找到DLL文件
Run or before running the script. The Playwright DLL only exists after NuGet restore.
dotnet builddotnet restore运行前先执行或。Playwright DLL仅在NuGet还原后才会存在。
playwright.ps1dotnet builddotnet restoreReferences
参考资料
This pattern is battle-tested in production projects:
该模式已在生产项目中经过验证:
Related Skills
相关技巧
- - Writing Playwright tests for Blazor applications
dotnet-skills:playwright-blazor - - Central Package Management setup
dotnet-skills:project-structure
- - 为Blazor应用编写Playwright测试
dotnet-skills:playwright-blazor - - 中央包管理配置
dotnet-skills:project-structure