WORKFLOW-APP/Dockerfile
SJCoetz e9b5324e1c build: remove empty public dir from docker image
Add a conditional cleanup step to remove the public directory if it does not exist or contains no files. This reduces the final docker image size since Next.js standalone builds automatically inline public assets when they are present, making the copied public directory often redundant.
2026-07-23 19:26:49 +02:00

88 lines
3.6 KiB
Docker

# ─────────────────────────────────────────────────────────────────
# Workflow PocketBase Frontend — Dockerfile
#
# Multi-stage build for a small production image:
# - deps: install everything
# - builder: compile the Next.js app (writes standalone output)
# - runner: copy the standalone build + public assets + .next/static
# onto the alpine image
#
# Image runs as non-root user `nextjs` on port 3000.
#
# Build context: project root (where package.json lives).
# Example:
# docker build -t workflow-frontend .
# docker run --rm -p 3000:3000 \
# -e NEXT_PUBLIC_BASE_URL=https://workflow.example.co.za \
# -e PB_URL=https://pb.agent.apphub.co.za \
# -e PB_TOKEN=... \
# workflow-frontend
# ─────────────────────────────────────────────────────────────────
# ─── 1. Deps ─────────────────────────────────────────────────────
FROM node:20-alpine AS deps
WORKDIR /app
COPY package.json package-lock.json* ./
RUN \
if [ -f package-lock.json ]; then npm ci; \
else npm install; \
fi
# ─── 2. Builder ──────────────────────────────────────────────────
FROM node:20-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
# Required at build-time so Next.js bakes the public URL into the
# client bundle. PB_TOKEN is NOT required here — it's only read
# server-side at runtime.
ARG NEXT_PUBLIC_BASE_URL
ENV NEXT_PUBLIC_BASE_URL=${NEXT_PUBLIC_BASE_URL}
# Disable telemetry; speeds up build; we don't need it.
ENV NEXT_TELEMETRY_DISABLED=1
RUN npm run build
# ─── 3. Runner ───────────────────────────────────────────────────
FROM node:20-alpine AS runner
WORKDIR /app
# wget is needed by the HEALTHCHECK below (not in node:20-alpine
# by default — busybox-extra ships it).
RUN apk add --no-cache wget
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
ENV PORT=3000
ENV HOSTNAME=0.0.0.0
# Non-root user
RUN addgroup --system --gid 1001 nodejs && \
adduser --system --uid 1001 nextjs
# Copy the standalone build (Next.js output tracing) + static assets.
# `public/` is optional (PWA manifest, favicons, robots.txt). Next
# inlines any source `public/` into the standalone build, so we only
# need to copy it if it actually exists. Projects without a public/
# dir (e.g. this one pre-PWA) no-op cleanly.
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
RUN if [ -d ./public ] && [ -n "$(ls -A ./public 2>/dev/null)" ]; then \
echo "public/ assets found in standalone build, keeping"; \
else \
rm -rf ./public 2>/dev/null || true; \
fi
USER nextjs
EXPOSE 3000
# Health check — Coolify / Docker can probe /api/pb/records/list and
# 401 / 500 is fine here (it means the app booted; PB may be
# unreachable but the proxy is running). A connection refused means
# the Next.js server hasn't bound yet.
HEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 \
CMD wget -qO- http://127.0.0.1:3000/api/pb/records/list?collection=ysterbaard_directors\&perPage=1 >/dev/null || exit 1
CMD ["node", "server.js"]