# syntax=docker/dockerfile:1 # ---- frontend build: React/Vite PWA -> static dist/ ---- FROM node:22-slim AS frontend-build WORKDIR /app/frontend COPY frontend/package.json frontend/package-lock.json ./ RUN npm ci COPY frontend/ . # Vite inlines VITE_* env vars at build time, so the Google client id has to # be supplied as a build arg: docker build --build-arg VITE_GOOGLE_CLIENT_ID=... ARG VITE_GOOGLE_CLIENT_ID ENV VITE_GOOGLE_CLIENT_ID=$VITE_GOOGLE_CLIENT_ID RUN npm run build # ---- backend build: TypeScript -> single esbuild bundle ---- FROM node:22-slim AS backend-build WORKDIR /app/backend COPY backend/package.json backend/package-lock.json ./ RUN npm ci COPY backend/ . RUN npm run build # ---- runtime: only prod deps + the two build outputs ---- FROM node:22-slim AS runtime ENV NODE_ENV=production WORKDIR /app # better-sqlite3 has a native binding, so it's installed for real here rather # than copied from another stage — same base image as backend-build, so the # compiled binary always matches what it runs on. COPY backend/package.json backend/package-lock.json ./ RUN npm ci --omit=dev && npm cache clean --force COPY --from=backend-build /app/backend/dist ./dist COPY --from=frontend-build /app/frontend/dist ./dist/public ENV PORT=4000 ENV DB_PATH=/app/data/eatme.db EXPOSE 4000 VOLUME ["/app/data"] CMD ["node", "dist/index.js"]