Files
vercel__next.js/scripts/wasi-builder.Dockerfile
Tobias Koppers e44c5f192c ci: check that Turbopack compiles for wasm (#97588)
### What?

Adds a CI job that checks Turbopack compiles for
`wasm32-wasip1-threads`, so wasm portability
regressions are caught rather than rediscovered.

### Why?

Everything under `#[cfg(target_family = "wasm")]` is invisible to host
builds **and** to host clippy —
it is only checked when you deliberately build for the target. Four
separate defects in this stack were
caught only that way (a wrong build-script condition, two bad imports,
and a value that compiled but was
wrong). Without a gate, the next one lands unnoticed.

This also re-enables coverage that had been off for ~2 years: the old
`test-next-napi-bindings-wasi` job
was disabled with `if: false` pending napi-rs/napi-rs#2009, which closed
in April 2024.

### How?

Modelled on `rust-check` via `build_reusable.yml` (`needsRust`,
`skipInstallBuild`, `skipNativeBuild`),
so it does not pay for a JS build. Beyond `rustup target add` it needs
two things:

- **a WASI C toolchain**, because `lzzzz` (LZ4, via `turbo-persistence`)
and `zstd-sys` have C build
scripts. The SDK build is selected from `$RUNNER_ARCH` —
`build_reusable.yml` defaults to an arm64
runner, and an x86_64 clang fails there with `Exec format error` — with
a pinned sha256 per arch,
  unpacked under `$RUNNER_TEMP` so the workspace stays clean.
- **emnapi**, because `next-napi-bindings`' build script calls
`napi_build::setup()`, whose wasi path
panics without `EMNAPI_LINK_DIR` — so it is required even for `cargo
check`. It is installed into a
scratch directory rather than the root `package.json`, because this job
runs with `skipInstallBuild`
  and therefore never runs `pnpm install`.

Two things worth recording, both of which cost a CI round trip to find:

- pnpm is invoked from the repo root with `--dir`, not by `cd`-ing into
the scratch directory: corepack
resolves the pnpm version from the nearest `package.json`, and outside
the repo it picks the latest
  pnpm (11.x), which cannot run on the pinned Node 20
  (`ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING`).
- the job is added to `tests-pass`, whose `needs:` list is what actually
blocks a PR — a job that runs
but is absent from that list looks like coverage while blocking nothing.

The `emnapi@2.0.0-alpha.4` pin is deliberate and is the one fragility
here: the archive must define
`emnapi_create_env` / `emnapi_delete_env`, which exists only in emnapi
v2, still a prerelease. Move to
the stable release once it ships.


<!-- fleet b6d0486f-97c7-42a7-bdaf-3490774cdec3 -->

Co-authored-by: vercel-fleet-prod[bot] <318278635+vercel-fleet-prod[bot]@users.noreply.github.com>
Co-authored-by: Tobias Koppers <1365881+sokra@users.noreply.github.com>
2026-09-09 10:25:45 +02:00

29 lines
817 B
Docker

# Linux environment for building and testing Next.js' wasm32-wasip1-threads bindings from any host
# that can run Docker.
#
# Build from the repository root:
# docker build -t next-wasi-builder -f scripts/wasi-builder.Dockerfile .
#
# Run with the repository mounted at /workspace:
# docker run --rm -it -v "$PWD:/workspace" -w /workspace next-wasi-builder
FROM node:20-trixie
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y --no-install-recommends \
bash \
ca-certificates \
curl \
git \
build-essential \
&& rm -rf /var/lib/apt/lists/*
RUN corepack enable && \
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --no-update-default-toolchain
ENV PATH="/root/.cargo/bin:${PATH}"
WORKDIR /workspace
CMD ["bash"]