# ─────────────────────────────────────────────────── # Coastal Timesheet — Frontend Dockerfile # Build: Node 22 Alpine → Serve: Nginx Alpine # ─────────────────────────────────────────────────── # ── Stage 1: Install dependencies ────────────────── FROM node:22-alpine AS deps WORKDIR /app # Copy package files (frontend lives in the frontend/ directory) COPY frontend/package.json frontend/package-lock.json* ./ # Install all dependencies (including devDependencies for build) RUN npm ci 2>/dev/null || npm install # ── Stage 2: Build ──────────────────────────────── FROM node:22-alpine AS builder WORKDIR /app # Copy dependencies COPY --from=deps /app/node_modules ./node_modules # Copy frontend source COPY frontend/ ./ # Set API URL for production build ARG VITE_API_URL=/api ENV VITE_API_URL=${VITE_API_URL} # Build the React app RUN npm run build # ── Stage 3: Serve with Nginx ───────────────────── FROM nginx:1.27-alpine AS runner # Remove default nginx config and static files RUN rm -rf /etc/nginx/conf.d/default.conf /usr/share/nginx/html/* # Copy built frontend assets COPY --from=builder /app/dist /usr/share/nginx/html # The nginx config is mounted via docker-compose volume # but we include a fallback in case it's run standalone COPY docker/nginx/default.conf /etc/nginx/conf.d/default.conf # Expose ports EXPOSE 80 443 # Nginx runs as non-root by default in alpine image # Health check HEALTHCHECK --interval=30s --timeout=5s --retries=3 \ CMD wget --no-verbose --tries=1 --spider http://localhost:80/ || exit 1 CMD ["nginx", "-g", "daemon off;"]