From dd8a695bde9c47fa7fc2a38d4d9199bda8da0bba Mon Sep 17 00:00:00 2001 From: Lazizbek Ergashev Date: Sat, 24 Oct 2026 03:32:19 +0500 Subject: [PATCH] fix(docker): link the pn, pnpx, and pnx aliases in the image (#17282) docker/install-pnpm.sh linked only `pnpm` into /usr/local/bin, so the image had no `pn`, `pnpx`, or `pnx`. The script now hardlinks the binary as each alias in /opt/pnpm and symlinks them onto PATH, as the npm package and self-update do for the native binary. Both the v12 binary and the v11 executable read the launch name from the hardlink and run `pnpm dlx` for `pnpx` and `pnx`. The docs recipe for copying /opt/pnpm into another image links the aliases too. The install script fails the build if `pn` does not print the installed version or `pnpx` and `pnx` do not run `pnpm dlx`. Fixes pnpm/pnpm#17275 --------- Co-authored-by: Zoltan Kochan Co-authored-by: Claude Opus 5.5 --- docker/README.md | 2 +- docker/install-pnpm.sh | 23 ++++++++++++++++++----- pnpm/docs/docker.md | 4 ++-- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/docker/README.md b/docker/README.md index b641e69531..ee48c296fc 100644 --- a/docker/README.md +++ b/docker/README.md @@ -26,7 +26,7 @@ To add pnpm to an existing image, such as `node:-alpine`, copy the whol ```dockerfile FROM node:24-alpine COPY --from=ghcr.io/pnpm/pnpm:12-alpine /opt/pnpm /opt/pnpm -RUN ln -s /opt/pnpm/pnpm /usr/local/bin/pnpm +RUN for bin in pnpm pn pnpx pnx; do ln -s "/opt/pnpm/$bin" "/usr/local/bin/$bin"; done ``` ## Supported platforms diff --git a/docker/install-pnpm.sh b/docker/install-pnpm.sh index b09816222c..f3a3a55e0e 100644 --- a/docker/install-pnpm.sh +++ b/docker/install-pnpm.sh @@ -30,8 +30,21 @@ test "$actual_sha" = "$expected_sha" || { tar -xzf /tmp/pnpm.tgz -C /opt/pnpm rm /tmp/pnpm.tgz ln -s /opt/pnpm/pnpm /usr/local/bin/pnpm -installed="$(pnpm --version)" -test "$installed" = "$PNPM_VERSION" || { - echo "pnpm version mismatch: expected $PNPM_VERSION, got $installed" >&2 - exit 1 -} +for alias in pn pnpx pnx; do + ln /opt/pnpm/pnpm "/opt/pnpm/$alias" + ln -s "/opt/pnpm/$alias" "/usr/local/bin/$alias" +done +for bin in pnpm pn; do + installed="$("$bin" --version)" + test "$installed" = "$PNPM_VERSION" || { + echo "$bin version mismatch: expected $PNPM_VERSION, got $installed" >&2 + exit 1 + } +done +for alias in pnpx pnx; do + help="$("$alias" --help)" + case "$help" in + *"pnpm dlx"*) ;; + *) echo "$alias does not run pnpm dlx" >&2; exit 1 ;; + esac +done diff --git a/pnpm/docs/docker.md b/pnpm/docs/docker.md index 43d8eb77b6..e26379a80c 100644 --- a/pnpm/docs/docker.md +++ b/pnpm/docs/docker.md @@ -33,13 +33,13 @@ Supported platforms: `linux/amd64`, `linux/arm64`. ### Adding pnpm to your own image -Copy `/opt/pnpm` from the image whose C library matches your base image, and link the binary onto `PATH`. +Copy `/opt/pnpm` from the image whose C library matches your base image, and link the binary and its `pn`, `pnpx`, and `pnx` aliases onto `PATH`. Copy the whole directory, because it also contains the `node-gyp` that pnpm uses to build native dependencies. ```dockerfile title="Dockerfile" FROM node:24-alpine COPY --from=ghcr.io/pnpm/pnpm:12-alpine /opt/pnpm /opt/pnpm -RUN ln -s /opt/pnpm/pnpm /usr/local/bin/pnpm +RUN for bin in pnpm pn pnpx pnx; do ln -s "/opt/pnpm/$bin" "/usr/local/bin/$bin"; done ``` For a Debian- or Ubuntu-based image, such as `node:24-slim`, copy from `ghcr.io/pnpm/pnpm:12` instead.