From 23512411a0d378d0e9d331a62025bca1fc8955df Mon Sep 17 00:00:00 2001 From: 4gray <4gray@users.noreply.github.com> Date: Sun, 26 Jul 2026 19:54:52 +0200 Subject: [PATCH] build(docker): move image to node 24 and install pnpm without corepack (#1265) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Supersedes #1250, whose 22 -> 26 bump failed the image build: `corepack enable` exits 127 because Node 25 unbundled Corepack. Both stages move to node:24-alpine, the current LTS line — Node 26 stays Current until October 2026, which is the wrong target for a self-hosted runtime image. pnpm is installed globally at the exact `packageManager` version, with the `+sha512...` suffix stripped, so the next base-image major is a one-line change instead of a broken build. --- docker/Dockerfile | 11 ++++++++--- docs/architecture/pwa-self-hosted.md | 5 ++++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 53368c8c7..86da3f98d 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,7 +1,7 @@ # The Nx builds below emit platform-independent JS/static assets. During # multi-arch publish builds, keep that heavy build stage on the native builder # platform instead of running Node/Nx through QEMU for linux/arm64. -FROM --platform=$BUILDPLATFORM node:22-alpine AS build +FROM --platform=$BUILDPLATFORM node:24-alpine AS build RUN apk add --no-cache python3 make g++ git @@ -11,7 +11,12 @@ COPY .npmrc ./ COPY package.json pnpm-lock.yaml ./ COPY patches ./patches -RUN corepack enable && pnpm install --frozen-lockfile --ignore-scripts +# Node 25 unbundled Corepack, so `corepack enable` cannot be the way pnpm gets +# installed here — it would break on the next base-image major. Install the +# exact pnpm from `packageManager` instead, which stays reproducible. +RUN PNPM_VERSION="$(node -p 'require("./package.json").packageManager.split("@")[1].split("+")[0]')" \ + && npm install --global "pnpm@${PNPM_VERSION}" \ + && pnpm install --frozen-lockfile --ignore-scripts COPY . . @@ -23,7 +28,7 @@ RUN node tools/build/inject-build-commit.mjs RUN pnpm nx build web --configuration=pwa RUN pnpm nx build web-backend -FROM node:22-alpine +FROM node:24-alpine RUN apk add --no-cache gettext nginx diff --git a/docs/architecture/pwa-self-hosted.md b/docs/architecture/pwa-self-hosted.md index da799457d..d95ee24ab 100644 --- a/docs/architecture/pwa-self-hosted.md +++ b/docs/architecture/pwa-self-hosted.md @@ -175,7 +175,10 @@ browser sidecar data. The Docker image has two stages: 1. Build stage installs dependencies and runs `web:pwa` plus `web-backend`. -2. Runtime stage uses `node:22-alpine` with nginx installed. nginx serves + pnpm is installed globally at the exact `packageManager` version rather than + through Corepack, which Node 25 unbundled, so the base-image major stays + free to move. +2. Runtime stage uses `node:24-alpine` with nginx installed. nginx serves `dist/apps/web` and proxies `/api/*` to the local Express backend. The entrypoint renders the nginx config from a `${PORT}` template, starts the backend, waits for `/health`, and then starts nginx. If either process exits