# ============================================================ # Stage 1 — Build # Node 22 Alpine: smallest image with full npm support # ============================================================ FROM node:22-alpine AS builder WORKDIR /app # Install dependencies first (layer cache — only re-runs if package.json changes) COPY package.json package-lock.json ./ RUN npm ci # Copy source COPY . . # VITE_* vars are Supabase public keys — safe for browser, baked into bundle at build time. # Using ARG only (no ENV) so values don't persist as image-layer env vars. ARG VITE_SUPABASE_URL ARG VITE_SUPABASE_ANON_KEY ARG VITE_SUPABASE_PUBLISHABLE_KEY # Pass vars inline so they're scoped to this RUN layer only RUN VITE_SUPABASE_URL="$VITE_SUPABASE_URL" \ VITE_SUPABASE_ANON_KEY="$VITE_SUPABASE_ANON_KEY" \ VITE_SUPABASE_PUBLISHABLE_KEY="$VITE_SUPABASE_PUBLISHABLE_KEY" \ npm run build # ============================================================ # Stage 2 — Serve # Nginx Alpine: ~25MB final image # ============================================================ FROM nginx:alpine AS runner # Replace default nginx config with SPA config COPY nginx.conf /etc/nginx/conf.d/default.conf # Copy built static files from builder COPY --from=builder /app/dist /usr/share/nginx/html EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]