# Pre-baked CI base image for Woodpecker pipelines. # # Purpose: eliminate the cold `pnpm install` that dominates every pipeline # (~731s median). This image ships the native toolchain (no per-run `apk add`) # AND a warm, content-addressable pnpm store with the dependency tree already # fetched and its musl native modules (better-sqlite3, node-pty, sqlite3, # canvas, sharp) compiled ONCE at build time. A pipeline `pnpm install # --frozen-lockfile --prefer-offline` then resolves from local hard-links in # tens of seconds. # # Rebuilt only when `pnpm-lock.yaml` or this Dockerfile change # (see .woodpecker/ci-image.yml). # # Node version is intentionally pinned to 22 (Active LTS at time of writing). # The node:22 -> node:24 bump lands as a SEPARATE follow-up PR so the cache # change carries zero runtime-version variables. FROM node:22-alpine # Native toolchain required to compile node-gyp deps on musl, plus the # postgresql-client used by the test step's pg_isready readiness probe. RUN apk add --no-cache python3 make g++ postgresql-client # Pin pnpm to the repo's packageManager version via corepack. RUN corepack enable && corepack prepare pnpm@10.6.2 --activate WORKDIR /app # Pin the store location so the pipeline can point `store-dir` at the same path. ENV PNPM_HOME=/root/.local/share/pnpm RUN pnpm config set store-dir /root/.local/share/pnpm/store # Warm the store + compile native modules once. `pnpm fetch` populates the # content-addressable store directly from the lockfile (no package.json / # workspace needed), so a baked store stays valid until the lockfile changes. COPY pnpm-lock.yaml ./ RUN pnpm fetch --frozen-lockfile