1- FROM node:22-alpine AS builder
1+ # syntax=docker/dockerfile:1
2+
3+ # ── Build stage — runs natively on the CI host (no QEMU) ─────────────────────
4+ # $BUILDPLATFORM is always the host arch (e.g. linux/amd64).
5+ # TypeScript/Astro compilation is pure JS so this is safe.
6+ FROM --platform=$BUILDPLATFORM node:22-alpine AS builder
27
38RUN apk add --no-cache python3 make g++ sqlite-dev
49
@@ -11,16 +16,30 @@ RUN npm ci && npm rebuild better-sqlite3
1116COPY . .
1217RUN npm run build
1318
14- # ── Production image ──────────────────────────────────
19+ # ── Prod deps — still on the BUILD platform, but targeting the right arch ─────
20+ # npm_config_arch tells node-pre-gyp to download / compile the native addon
21+ # for the TARGET architecture instead of the host architecture.
22+ FROM --platform=$BUILDPLATFORM node:22-alpine AS prod-deps
23+ ARG TARGETARCH
24+
25+ RUN apk add --no-cache python3 make g++ sqlite-dev
26+
27+ WORKDIR /app
28+ COPY package.json package-lock.json ./
29+
30+ # Map Docker arch names (amd64/arm64) to npm arch names (x64/arm64)
31+ RUN NPM_ARCH=$([ "$TARGETARCH" = "amd64" ] && echo "x64" || echo "$TARGETARCH" ) && \
32+ npm_config_arch=$NPM_ARCH npm ci --omit=dev
33+
34+ # ── Production image ──────────────────────────────────────────────────────────
1535FROM node:22-alpine AS runner
1636
1737WORKDIR /app
1838
19- # Copy only what's needed to run
20- COPY --from=builder /app/dist ./dist
21- COPY --from=builder /app/node_modules ./node_modules
22- COPY --from=builder /app/package.json ./package.json
23- COPY --from=builder /app/wasm-wrappers ./wasm-wrappers
39+ COPY --from=builder /app/dist ./dist
40+ COPY --from=builder /app/wasm-wrappers ./wasm-wrappers
41+ COPY --from=builder /app/package.json ./package.json
42+ COPY --from=prod-deps /app/node_modules ./node_modules
2443
2544ENV HOST=0.0.0.0
2645ENV PORT=4321
0 commit comments