ci: run Linux Playwright jobs in prebuilt Microsoft container (#93794)
## Summary
Runs Linux `build_reusable.yml` jobs that need Playwright inside
Microsoft's prebuilt
[`mcr.microsoft.com/playwright:v1.58.2-noble`](https://mcr.microsoft.com/en-us/product/playwright/about)
image. The image already contains Chromium, Firefox, WebKit, and their
system dependencies under `/ms-playwright`, so Linux test shards no
longer spend each job downloading browsers and installing apt deps.
- Adds a `playwrightDockerImage` input, defaulting to the Ubuntu 24.04
(`-noble`) Playwright image so glibc matches the `ubuntu-latest` runners
that build `next-swc.linux-x64-gnu.node`.
- Adds a `usePlaywrightContainer` input so jobs can opt out.
`test-next-swc-wasm` opts out because its `afterBuild` step needs
`rustup`, which is not in the Playwright image.
- Skips `pnpm playwright install --with-deps` for Linux jobs running in
the image; Windows jobs and opted-out jobs still install Playwright at
runtime.
- Enables the pnpm store cache inside container jobs because the
container filesystem is ephemeral even when the host runner is
persistent.
### Container condition
The Playwright image is used when all of the following are true:
- `inputs.needsPlaywright != 'no'`
- `inputs.skipInstallBuild != 'yes'`
- `inputs.usePlaywrightContainer != 'no'`
- The runner is not Windows
Otherwise `container.image` evaluates to `''` and the job runs directly
on the runner.
### Compatibility fixes
The Microsoft image is browser-focused, so this PR adds a few CI setup
fixes before the existing test workflow runs:
| Concern | Fix |
| --- | --- |
| Missing `jq` / `unzip` / native build toolchain | Install `jq`,
`unzip`, and `build-essential` inside Linux container jobs. |
| Firefox refuses `$HOME` not owned by the current user | Re-own GitHub
Actions' mounted `/github/home` directory for the root user used by the
job. |
| Git sees the mounted workspace as dubious ownership | Mark
`$GITHUB_WORKSPACE` as a safe directory for Git. |
| Standalone tests bind to Docker's generated `HOSTNAME` | Set container
`HOSTNAME=0.0.0.0`. |
| `getStorageDirectory()` treats Docker storage as ephemeral | Add
`NEXT_IGNORE_IS_DOCKER=1` for CI container jobs and honor it in
`cache-dir.ts` so deterministic-build tests keep using `dist/cache`. |
| `localhost` IPv4/IPv6 mismatch in analyze tests | Let the analyze
server listen on both IPv4 and IPv6 localhost addresses. |
| Nx fixture can race in CI before Next.js starts | Disable Nx isolated
plugins for the `nx-handling` fixture scripts. |
## Timing
Earlier comparison runs showed the Playwright install/setup portion
across 82 matched Linux jobs dropping from about **3 h 03 m total** on
canary to about **39 m 24 s total** with the containerized setup,
roughly **1 m 45 s saved per job** on average. Test execution itself is
excluded from that comparison because shard balancing makes it noisy.
## Test plan
- [x] Latest PR CI run
[`26121297957`](https://github.com/vercel/next.js/actions/runs/26121297957)
completed successfully with 0 failed jobs.
- [x] Linux Playwright matrices are green, including `test dev`, `test
prod`, `test turbopack *`, `test cache components *`, `test node streams
*`, and changed-test lanes.
- [x] Linux non-Playwright jobs remain green on the bare runner,
including `lint`, `types and precompiled`, `rust check`, `test cargo
unit`, and `test unit`.
- [x] `test-next-swc-wasm` is green while opted out of the container via
`usePlaywrightContainer: 'no'`.
- [x] Windows jobs are green and continue to use runtime Playwright
installation.
<!-- NEXT_JS_LLM_PR -->
---------
Co-authored-by: Cursor <cursoragent@cursor.com>