- Add inline comments to docker-compose.yml explaining the 5 key rules (expose vs ports, DB host, DB name persistence, no Traefik labels) - Add comments to Dockerfile explaining multi-stage build, layer caching, and why .dockerignore excludes client/dist - Add comments to .dockerignore explaining each exclusion - Fix dev script: use nodemon (auto-restart) instead of node for server.js - Add postinstall script to auto-install client deps (cd client && npm install) - Fix SPA fallback: bare return → next() to prevent hanging requests - Add root package-lock.json for deterministic server dependency installs - Remove committed tsconfig.tsbuildinfo build artifact, add *.tsbuildinfo to .gitignore - Update README: simpler install (npm install handles everything), reference SAAC_DEPLOYMENT.md, use npx instead of pnpm dlx for shadcn components
58 lines
1.9 KiB
Docker
58 lines
1.9 KiB
Docker
# Multi-stage Dockerfile for React + Express application
|
|
# See SAAC_DEPLOYMENT.md for deployment rules and common mistakes.
|
|
#
|
|
# Stage 1 (builder): Installs client deps and builds the React app with Vite.
|
|
# Stage 2 (production): Installs server deps only, copies built React output.
|
|
#
|
|
# The .dockerignore excludes client/dist from the build context — this is
|
|
# intentional. The builder stage creates a fresh dist/ inside the container,
|
|
# and COPY --from=builder copies it between stages (bypasses .dockerignore).
|
|
|
|
# --- Stage 1: Build React frontend ---
|
|
FROM node:20-alpine AS builder
|
|
|
|
WORKDIR /app/client
|
|
|
|
# Install client dependencies first (layer caching — only re-runs if package*.json change)
|
|
COPY client/package*.json ./
|
|
RUN npm install
|
|
|
|
# Copy client source and build
|
|
COPY client/ ./
|
|
RUN npm run build
|
|
|
|
# --- Stage 2: Production server ---
|
|
FROM node:20-alpine
|
|
|
|
ARG SOURCE_COMMIT=unknown
|
|
ARG APP_VERSION=1.0.0
|
|
|
|
WORKDIR /app
|
|
|
|
# curl is required for the Docker healthcheck below
|
|
RUN apk add --no-cache curl
|
|
|
|
# Install server dependencies only (not devDependencies — they're not needed in production).
|
|
# If your app needs devDependencies for a build step (e.g. TypeScript), install ALL deps
|
|
# first, run the build, then prune: RUN npm install && npm run build && npm prune --production
|
|
COPY package*.json ./
|
|
RUN npm install --production
|
|
|
|
# Copy server code
|
|
COPY server.js ./
|
|
|
|
# Copy built React app from the builder stage (not from host — .dockerignore doesn't apply)
|
|
COPY --from=builder /app/client/dist ./client/dist
|
|
|
|
ENV GIT_COMMIT=${SOURCE_COMMIT} \
|
|
APP_VERSION=${APP_VERSION}
|
|
|
|
# Use "expose" in docker-compose.yml, not "ports". This EXPOSE is just documentation.
|
|
EXPOSE 3000
|
|
|
|
# Healthcheck — must match the healthcheck in docker-compose.yml
|
|
HEALTHCHECK --interval=10s --timeout=3s --start-period=5s --retries=2 \
|
|
CMD curl -f http://localhost:3000/health || exit 1
|
|
|
|
CMD ["node", "server.js"]
|