1- # ============================================================
2- # STAGE 1: Build base (install dependencies)
3- # ============================================================
4- FROM helsinki.azurecr.io/ubi9/nodejs-24-pnpm-builder-base AS appbase
1+ # ===============================================
2+ FROM registry.access.redhat.com/ubi9/nodejs-20 AS appbase
3+ # ===============================================
4+
5+ # install yarn
6+ USER root
7+ RUN curl --silent --location https://dl.yarnpkg.com/rpm/yarn.repo | tee /etc/yum.repos.d/yarn.repo
8+ RUN yum -y install yarn
9+
510WORKDIR /app
611
7- # Defaults to production; compose overrides this to development on build and run.
8- ARG NODE_ENV=production
9- ENV NODE_ENV=$NODE_ENV
10-
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.
14- COPY --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
22- COPY --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).
31- COPY --chown=default:root \
32- index.html \
33- vite.config.ts \
34- tsconfig.json \
35- vite-env.d.ts \
36- .babelrc \
37- .eslintrc.cjs \
38- .eslintignore \
39- .prettierrc.json \
40- .prettierignore \
41- ./
42- COPY --chown=default:root src ./src
43-
44- # ============================================================
45- # STAGE 2: Development
46- # ============================================================
12+ # Offical image has npm log verbosity as info. More info - https://github.com/nodejs/docker-node#verbosity
13+ ENV NPM_CONFIG_LOGLEVEL warn
14+
15+ # set our node environment, either development or production
16+ # defaults to production, compose overrides this to development on build and run
17+ ARG NODE_ENV=${NODE_ENV:-"production" }
18+ ENV NODE_ENV $NODE_ENV
19+
20+ # Global npm deps in a non-root user directory
21+ ENV NPM_CONFIG_PREFIX=/app/.npm-global
22+ ENV PATH=$PATH:/app/.npm-global/bin
23+
24+ # Yarn
25+ ENV YARN_VERSION 1.22.22
26+ RUN yarn policies set-version ${YARN_VERSION}
27+
28+ # Copy package.json and package-lock.json/yarn.lock files
29+ COPY --chown=default:root package*.json *yarn* ./
30+
31+ # Install npm dependencies
32+ ENV PATH /app/node_modules/.bin:$PATH
33+
34+ RUN yarn install --frozen-lockfile --ignore-scripts && yarn cache clean --force
35+
36+ # =============================
4737FROM appbase AS development
48- WORKDIR /app
38+ # =============================
4939
40+ # Set NODE_ENV to development in the development container
5041ARG NODE_ENV=development
51- ENV NODE_ENV= $NODE_ENV
42+ ENV NODE_ENV $NODE_ENV
5243
5344# Enable hot reload by default by polling for file changes.
5445#
@@ -57,51 +48,77 @@ ENV NODE_ENV=$NODE_ENV
5748ARG CHOKIDAR_USEPOLLING=true
5849ENV CHOKIDAR_USEPOLLING=${CHOKIDAR_USEPOLLING}
5950
60- # `pnpm start` runs update-runtime-env then vite (port from PORT env, default 3001).
61- CMD [ "pnpm" , "start" , "--no-open" , "--host" ]
51+ # copy in our source code last, as it changes the most
52+ COPY --chown=default:root . .
6253
63- # ============================================================
64- # STAGE 3: Static builder for production
65- # ============================================================
66- FROM appbase AS staticbuilder
54+ # Bake package.json start command into the image
55+ CMD ["yarn" , "start" , "--no-open" , "--host" ]
6756
68- # VITE_CSP_REPORT_URI is substituted into index.html's CSP at *build* time by
69- # Vite (it is not a runtime value). Default to empty so the placeholder is not
70- # left unreplaced in the output.
57+ # ===================================
58+ FROM appbase AS staticbuilder
59+ # ===================================
60+
61+ ARG VITE_API_URI
62+ ARG VITE_OIDC_SERVER_TYPE
63+ ARG VITE_OIDC_RETURN_TYPE
64+ ARG VITE_OIDC_AUTHORITY
65+ ARG VITE_OIDC_CLIENT_ID
66+ ARG VITE_OIDC_KUKKUU_API_CLIENT_ID
67+ ARG VITE_OIDC_SCOPE
68+ ARG VITE_OIDC_AUDIENCES
69+ ARG VITE_OIDC_AUTOMATIC_SILENT_RENEW_ENABLED
70+ ARG VITE_OIDC_SESSION_POLLING_INTERVAL_MS
71+ ARG VITE_KUKKUU_API_OIDC_SCOPE
72+ ARG VITE_SENTRY_ENVIRONMENT
73+ ARG VITE_SENTRY_DSN
74+ ARG VITE_SENTRY_TRACES_SAMPLE_RATE
75+ ARG VITE_SENTRY_TRACE_PROPAGATION_TARGETS
76+ ARG VITE_SENTRY_REPLAYS_SESSION_SAMPLE_RATE
77+ ARG VITE_SENTRY_REPLAYS_ON_ERROR_SAMPLE_RATE
7178ARG VITE_CSP_REPORT_URI
79+ ARG VITE_IS_TEST_ENVIRONMENT
80+ ARG VITE_BUILDTIME
81+ ARG VITE_SENTRY_RELEASE
82+ ARG VITE_COMMITHASH
83+ ARG VITE_IDLE_TIMEOUT_IN_MS
84+ ARG NODE_OPTIONS
85+
86+ # Fix FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed -
87+ # JavaScript heap out of memory: https://github.com/vitejs/vite/issues/2433.
88+ ENV NODE_OPTIONS=${NODE_OPTIONS}
7289ENV VITE_CSP_REPORT_URI=${VITE_CSP_REPORT_URI:-"" }
7390
74- RUN pnpm build
75-
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
91+ # Use template and inject the environment variables into .prod/nginx.conf
92+ ENV VITE_BUILDTIME=${VITE_BUILDTIME:-"" }
93+ ENV VITE_RELEASE=${VITE_SENTRY_RELEASE:-"" }
94+ ENV VITE_COMMITHASH=${VITE_COMMITHASH:-"" }
95+ COPY .prod/nginx.conf.template /tmp/.prod/nginx.conf.template
96+ RUN export APP_VERSION=$(yarn --silent app:version) && \
97+ envsubst '${APP_VERSION},${VITE_BUILDTIME},${VITE_RELEASE},${VITE_COMMITHASH}' < \
98+ "/tmp/.prod/nginx.conf.template" > \
99+ "/tmp/.prod/nginx.conf"
100+
101+ COPY . /app
102+ RUN yarn build
103+
104+ # =============================
105+ FROM registry.access.redhat.com/ubi9/nginx-122 AS production
106+ # =============================
107+ # Add application sources to a directory that the assemble script expects them
108+ # and set permissions so that the container runs without root access
109+ USER root
110+
111+ RUN chgrp -R 0 /usr/share/nginx/html && \
112+ chmod -R g=u /usr/share/nginx/html
113+
114+ # Copy static build
115+ COPY --from=staticbuilder /app/build /usr/share/nginx/html
116+ # Copy nginx config
117+ COPY --from=staticbuilder /tmp/.prod/nginx.conf /etc/nginx/nginx.conf
83118
84- # ============================================================
85- # STAGE 4: Production runtime
86- # ============================================================
87- FROM helsinki.azurecr.io/ubi10/nginx-126-spa-standard AS production
119+ USER 1001
88120
89- # 1. Copy the compiled assets.
90- COPY --from=staticbuilder /app/build /usr/share/ nginx/html
121+ # Run script uses standard ways to run the application
122+ CMD [ "/bin/bash" , "-c" , " nginx -g \" daemon off; \" " ]
91123
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.
97- WORKDIR /usr/share/nginx/html
98- COPY --from=staticbuilder /app/.env.runtime ./.env
99-
100- # 3. package.json powers the base image's /readiness version endpoint.
101- COPY package.json .
102-
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
124+ EXPOSE 8080
0 commit comments