22# STAGE 1: Build base (install dependencies)
33# ============================================================
44FROM helsinki.azurecr.io/ubi9/nodejs-24-pnpm-builder-base AS appbase
5- WORKDIR /app
6-
7- # Defaults to production; compose overrides this to development on build and run.
8- ARG NODE_ENV=production
9- ENV NODE_ENV=$NODE_ENV
105
11- # 1. Install dependencies (cached unless the manifests change).
12- # corepack in the base image uses the pnpm version from package.json's
13- # "packageManager" field automatically.
6+ # 1. Copy only necessary files for build
147COPY --chown=default:root package.json pnpm-lock.yaml pnpm-workspace.yaml ./
15- RUN pnpm install --frozen-lockfile --ignore-scripts && pnpm store prune
16-
17- # 2. Generate a build-time public/env-config.js. Its *contents* are overwritten
18- # at container start by the base image's env.sh with the real runtime values.
19- # update-runtime-env only needs the script, the public/ output dir and the .env
20- # key templates, so copy just those — editing src/ won't invalidate this layer.
21- COPY --chown=default:root scripts ./scripts
228COPY --chown=default:root public ./public
23- COPY --chown=default:root .env* ./
24- RUN pnpm update-runtime-env
25-
26- # 3. Copy only the sources the production build (`tsc && vite build`) consumes.
27- # tsconfig "include" is ["src"]; the build also reads these root configs — Vite
28- # itself, the babel presets used by @vitejs/plugin-react, and the eslint/prettier
29- # configs run by @nabla/vite-plugin-eslint. Tests, docs, codegen and other
30- # tooling are intentionally left out (and also pruned via .dockerignore).
9+ COPY --chown=default:root scripts ./scripts
3110COPY --chown=default:root \
3211 index.html \
3312 vite.config.ts \
@@ -38,15 +17,24 @@ COPY --chown=default:root \
3817 .eslintignore \
3918 .prettierrc.json \
4019 .prettierignore \
20+ .env* \
4121 ./
42- COPY --chown=default:root src ./src
22+ COPY --chown=default:root ./src ./src
23+
24+ # 2. Run the install and update-runtime-env script
25+ # corepack in the base image will automatically use the version of pnpm
26+ # defined in your package.json 'packageManager' field if present.
27+ RUN pnpm install --frozen-lockfile --ignore-scripts && pnpm store prune
28+ RUN pnpm update-runtime-env
4329
4430# ============================================================
4531# STAGE 2: Development
4632# ============================================================
4733FROM appbase AS development
34+
4835WORKDIR /app
4936
37+ # Set NODE_ENV to development in the development container
5038ARG NODE_ENV=development
5139ENV NODE_ENV=$NODE_ENV
5240
@@ -57,6 +45,8 @@ ENV NODE_ENV=$NODE_ENV
5745ARG CHOKIDAR_USEPOLLING=true
5846ENV CHOKIDAR_USEPOLLING=${CHOKIDAR_USEPOLLING}
5947
48+ EXPOSE 8080
49+
6050# `pnpm start` runs update-runtime-env then vite (port from PORT env, default 3001).
6151CMD ["pnpm" , "start" , "--no-open" , "--host" ]
6252
@@ -73,14 +63,6 @@ ENV VITE_CSP_REPORT_URI=${VITE_CSP_REPORT_URI:-""}
7363
7464RUN pnpm build
7565
76- # Produce a sanitized runtime env template for the production image. The base
77- # image's env.sh is a naive KEY=VALUE parser: it does NOT skip comments or blank
78- # lines, so any "# comment"/blank line in .env makes it emit an empty-key entry
79- # (`: ""`) or duplicate the previous key — corrupting env-config.js into invalid
80- # JavaScript (SyntaxError at load → window._env_ undefined → app can't boot).
81- # Keep only `KEY=VALUE` lines so env.sh always generates valid JS.
82- RUN grep -E '^[A-Za-z_][A-Za-z0-9_]*=' .env.example > .env.runtime
83-
8466# ============================================================
8567# STAGE 4: Production runtime
8668# ============================================================
@@ -89,19 +71,15 @@ FROM helsinki.azurecr.io/ubi10/nginx-126-spa-standard AS production
8971# 1. Copy the compiled assets.
9072COPY --from=staticbuilder /app/build /usr/share/nginx/html
9173
92- # 2. Runtime env injection inputs (env.sh from the base image reads these).
93- # .env lists which keys to expose in env-config.js; the values are overwritten
94- # at container start with the real runtime environment. Use the sanitized,
95- # comment-free template (see staticbuilder) — the base image's env.sh cannot
96- # parse comments/blank lines and would otherwise emit invalid JavaScript.
74+ # 2. Setup Runtime Env Injection
75+ # env.sh is provided by the base image
9776WORKDIR /usr/share/nginx/html
98- COPY --from=staticbuilder /app/ .env.runtime ./.env
77+ COPY .env .
9978
100- # 3. package.json powers the base image's /readiness version endpoint.
79+ # 3. Inject Versioning for the /readiness endpoint from package.json using base image
10180COPY package.json .
10281
103- # Inherited from the base image:
104- # - env.sh at /usr/share/nginx/html/env.sh
105- # - USER 1001
106- # - EXPOSE 8080
107- # - ENTRYPOINT/CMD
82+ # - env.sh (Inherited from base image at /usr/share/nginx/html/env.sh)
83+ # - USER 1001 (Inherited from base image)
84+ # - EXPOSE 8080 (Inherited from base image)
85+ # - ENTRYPOINT/CMD (Inherited from base image)
0 commit comments