# LifeTrack web — React/Vite build served by nginx. # Build context = repository root (docker-compose.yml). FROM node:20-alpine AS build WORKDIR /build # Cap the V8 heap on small hosts (the self-hosted target has ~1 GB of usable # RAM and `vite build` bundles echarts): docker compose passes NODE_OPTIONS # through, empty by default so a normal machine keeps node's own heuristics. ARG NODE_OPTIONS="" ENV NODE_OPTIONS=$NODE_OPTIONS # Explicit names (not package*.json): a missing lockfile must fail here, loudly, # instead of turning into a confusing `npm ci` error. COPY apps/web/package.json apps/web/package-lock.json ./ RUN npm ci --no-audit --no-fund COPY apps/web/ ./ RUN npm run build FROM nginx:1.27-alpine COPY docker/nginx.conf /etc/nginx/conf.d/default.conf COPY --from=build /build/dist /usr/share/nginx/html EXPOSE 80 # busybox wget ships with nginx:alpine; -O /dev/null keeps it out of the fs. HEALTHCHECK --interval=15s --timeout=5s --start-period=10s --retries=3 \ CMD ["wget", "-q", "-O", "/dev/null", "http://127.0.0.1/index.html"]