# Multi-stage build for TOD Frontend # Stage 1: build — Node.js build environment FROM node:20-alpine AS builder # Cap Node.js heap to 512 MB so tsc + vite build don't OOM a low-RAM server. # Vite's bundler defaults to using all available heap; on a 2-4 GB machine that # competes directly with the Go and Python builds happening in parallel. ENV NODE_OPTIONS="--max-old-space-size=1024" WORKDIR /build # Copy package files first (layer cache optimization) COPY frontend/package.json frontend/package-lock.json* ./ # Install dependencies RUN npm ci --ignore-scripts # Copy frontend source and build # Note: skip tsc type-check in Docker build (esbuild handles transpilation). # Run `npm run build` locally or in CI for full type-checking. COPY frontend/ . RUN npx vite build # Stage 2: runtime — nginx serving static SPA files FROM nginx:alpine AS runtime # Remove default nginx config RUN rm /etc/nginx/conf.d/default.conf # Custom nginx config for SPA routing (all routes -> index.html) COPY infrastructure/docker/nginx-spa.conf /etc/nginx/conf.d/default.conf # Copy built assets from builder stage COPY --from=builder /build/dist /usr/share/nginx/html # nginx runs as nginx user (non-root by convention) EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]