| # ============================================================================ | |
| # Structured Data Extraction β UI image | |
| # | |
| # Multi-stage build: stage 1 (node) runs the Vite production build, stage 2 | |
| # (nginx) serves the resulting static bundle and proxies /api to the api | |
| # container. Nothing from node_modules survives into the runtime image. | |
| # ============================================================================ | |
| # ---------- Stage 1: build the Vite bundle ----------------------------------- | |
| FROM node:20-alpine AS builder | |
| WORKDIR /ui | |
| # Copy package manifests first β this lets Docker cache the npm install | |
| # layer across code-only changes. | |
| COPY ui/package.json ui/package-lock.json ./ | |
| RUN npm ci --no-audit --no-fund | |
| # Copy the rest of the ui source and build. | |
| COPY ui/ ./ | |
| RUN npm run build | |
| # ---------- Stage 2: serve with nginx ---------------------------------------- | |
| FROM nginx:1.27-alpine AS runtime | |
| # Custom nginx config β proxies /api to the api container. | |
| COPY docker/nginx.conf /etc/nginx/conf.d/default.conf | |
| # Remove the stock nginx config that listens on :80 β we listen on :5173 only. | |
| RUN rm -f /etc/nginx/conf.d/default.conf.bak && \ | |
| sed -i '/listen 80;/d' /etc/nginx/nginx.conf 2>/dev/null || true | |
| # Copy the built bundle. | |
| COPY --from=builder /ui/dist /usr/share/nginx/html | |
| EXPOSE 5173 | |
| # nginx:alpine runs as root by default β nginx workers drop to `nginx` user | |
| # themselves once bound to the port, so we leave the entrypoint alone. | |
| HEALTHCHECK --interval=15s --timeout=3s --start-period=5s --retries=3 \ | |
| CMD wget -qO- http://localhost:5173/ >/dev/null || exit 1 | |
| CMD ["nginx", "-g", "daemon off;"] | |