Fix docker file

This commit is contained in:
khalid@traclabs.com
2026-05-23 03:42:05 -05:00
parent b1fb6fa3aa
commit 6127e7b781

View File

@@ -1,40 +1,104 @@
# Multi-stage Dockerfile.
#
# Why two stages
# ──────────────
# `canvas` is a native-binding npm package. It needs Cairo/Pango/etc.
# at runtime, and python3+make+g++ at install-time to compile its
# native bindings (no prebuilt binary covers the alpine musl+napi+linux
# combination at this canvas version; prebuild-install falls back to
# node-gyp, which needs the compile toolchain).
#
# The naive single-stage approach would either:
# (a) keep python3+make+g++ in the final image — inflates the image
# by ~200MB of build tools nothing uses at runtime, or
# (b) try to install --omit=dev in a runtime-only image — fails
# because canvas tries to compile and has no python (this was
# the bug fixed in this revision).
#
# Two-stage solves both: install + compile + prune dev deps in the
# builder (which has the toolchain), then COPY the resulting
# node_modules into a slim runtime that only carries the C runtime
# libs canvas needs at execution time.
# ─────────────────────────────────────────────────────────────────
# Stage 1: builder
# Installs all deps (including dev), compiles native bindings,
# builds the Vite bundle, then prunes dev deps so node_modules is
# production-ready before we copy it.
# ─────────────────────────────────────────────────────────────────
FROM node:20-alpine AS builder
RUN apk add --no-cache cairo-dev pango-dev libjpeg-turbo-dev giflib-dev librsvg-dev pixman-dev python3 make g++
# Native-binding build prerequisites:
# • python3 / make / g++ — node-gyp toolchain for compiling canvas
# • cairo-dev / pango-dev / etc. — headers canvas links against
# These stay in the builder stage only; the runtime stage carries
# the matching runtime libraries (no -dev suffix) without the
# toolchain.
RUN apk add --no-cache \
cairo-dev pango-dev libjpeg-turbo-dev giflib-dev librsvg-dev pixman-dev \
python3 make g++
WORKDIR /app
# Copy package manifests first so docker can cache the npm install
# layer when only application source changes.
COPY package*.json ./
RUN npm install
COPY . .
# Pull Google Fonts into ./fonts/ so they end up in the runtime image. If the
# build host has no network this step will produce missing-variant warnings;
# the build still succeeds and the server falls back to system fonts.
# Pull Google Fonts into ./fonts/ so they end up in the runtime image.
# If the build host has no network this step will produce missing-variant
# warnings; the build still succeeds and the server falls back to system
# fonts.
RUN npm run fetch-fonts || echo "Font fetch had warnings; continuing with whatever was downloaded."
RUN npm run build
# Drop dev dependencies (vitest, playwright, eslint, etc.) so the
# node_modules we copy to runtime is production-only. This is the
# step that was missing before — without it, the runtime stage had
# to re-run `npm install` from scratch, which would re-trigger
# canvas's native compile in an image that doesn't have the
# toolchain. By pruning here, the runtime stage just copies the
# already-compiled directory.
RUN npm prune --production
# ─────────────────────────────────────────────────────────────────
# Stage 2: runtime
# Carries only the runtime C libraries canvas links against plus
# the fonts the export pipeline needs. node_modules is copied
# whole from the builder; no `npm install` happens here.
# ─────────────────────────────────────────────────────────────────
FROM node:20-alpine
# Cairo + Pango are required by node-canvas at runtime.
# The font packages cover the proprietary template families (Impact, Times,
# Courier, Arial) via free equivalents that fontconfig will alias, plus emoji
# rendering for sticker exports.
# The font packages cover the proprietary template families (Impact,
# Times, Courier, Arial) via free equivalents that fontconfig will
# alias, plus emoji rendering for sticker exports.
RUN apk add --no-cache \
cairo pango libjpeg-turbo giflib librsvg pixman \
ttf-liberation ttf-dejavu font-noto font-noto-emoji \
fontconfig
WORKDIR /app
COPY package*.json ./
RUN npm install --omit=dev
# Bring the production node_modules over from the builder rather
# than installing fresh. This carries the already-compiled canvas
# .node binary without needing python/make/g++ in this stage.
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package*.json ./
# Application files. server.js is the entry point; dist/ is the
# Vite build output served as static; fonts/ is the result of
# fetch-fonts above.
COPY server.js ./
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/fonts ./fonts
RUN mkdir -p /app/uploads /app/exports
# Refresh fontconfig's cache so the newly-copied custom fonts are discoverable.
# Refresh fontconfig's cache so the newly-copied custom fonts are
# discoverable.
RUN fc-cache -f /app/fonts || true
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \