Skip to content

Commit c5088eb

Browse files
committed
utilize better RUNTIME environment variables
1 parent 29ecc58 commit c5088eb

File tree

7 files changed

+59
-79
lines changed

7 files changed

+59
-79
lines changed

docker-compose.dev.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,8 @@ services:
7575
ports:
7676
- "3000:80"
7777
environment:
78-
ISSUER_URI: "http://localhost:8080/realms/tasks"
79-
CLIENT_ID: "tasks-web"
78+
RUNTIME_ISSUER_URI: "http://localhost:8080/realms/tasks"
79+
RUNTIME_CLIENT_ID: "tasks-web"
8080
depends_on:
8181
- backend
8282

web/.dockerignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
build/
2+
node_modules/
3+
.env*

web/Dockerfile

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,43 @@
11
FROM node:22-alpine AS base
22

3-
43
FROM base AS deps
5-
64
RUN apk add --no-cache libc6-compat
7-
85
WORKDIR /app
9-
106
COPY package.json package-lock.json ./
11-
127
RUN npm ci
138

14-
159
FROM base AS builder
16-
1710
WORKDIR /app
18-
1911
COPY --from=deps /app/node_modules ./node_modules
2012
COPY . .
21-
2213
RUN npm run build
2314

24-
2515
FROM base
26-
2716
WORKDIR /app
28-
2917
ENV NODE_ENV=production
3018
ENV PORT=80
3119
ENV HOSTNAME="0.0.0.0"
3220

33-
RUN apk add --no-cache libcap \
34-
&& setcap 'cap_net_bind_service=+ep' /usr/local/bin/node
21+
RUN apk add --no-cache libcap && setcap 'cap_net_bind_service=+ep' /usr/local/bin/node
3522

3623
RUN addgroup --system --gid 1001 nodejs
3724
RUN adduser --system --uid 1001 nextjs
3825

39-
COPY --from=builder /app/public ./public
26+
COPY --from=builder --chown=nextjs:nodejs /app/public ./public
4027
COPY --from=builder --chown=nextjs:nodejs /app/build/standalone ./
4128
COPY --from=builder --chown=nextjs:nodejs /app/build/static ./build/static
4229

43-
USER nextjs
30+
RUN printf '#!/bin/sh\n\
31+
echo "window.__ENV = {" > /app/public/env-config.js\n\
32+
env | grep "^RUNTIME_" | while read -r line; do\n\
33+
key=$(echo "$line" | cut -d "=" -f 1)\n\
34+
val=$(echo "$line" | cut -d "=" -f 2-)\n\
35+
echo " \"$key\": \"$val\"," >> /app/public/env-config.js\n\
36+
done\n\
37+
echo "}" >> /app/public/env-config.js\n\
38+
exec "$@"' > /app/entrypoint.sh && chmod +x /app/entrypoint.sh
4439

40+
USER nextjs
4541
EXPOSE 80
46-
42+
ENTRYPOINT ["/app/entrypoint.sh"]
4743
CMD ["node", "server.js"]

web/api/gql/fetcher.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,10 @@ export const fetcher = <TData, TVariables extends object | undefined>(
1717

1818
const headers: HeadersInit = {};
1919

20-
console.log(token, user);
21-
2220
if (token) {
2321
headers['Authorization'] = `Bearer ${token}`;
2422
document.cookie = `access_token=${token}; path=/; secure; samesite=strict`;
2523
}
26-
console.log(headers);
2724

2825
const hasFile =
2926
variables &&

web/environment.d.ts

Lines changed: 0 additions & 18 deletions
This file was deleted.

web/pages/_document.tsx

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,25 @@ import Document, { Html, Head, Main, NextScript } from 'next/document'
33

44
class MyDocument extends Document {
55
render() {
6-
const publicEnv = Object.keys(publicEnvSchema.shape).reduce((acc, key) => {
6+
const isDev = process.env.NODE_ENV !== 'production'
7+
8+
const devEnv = isDev ? Object.keys(publicEnvSchema.shape).reduce((acc, key) => {
79
acc[key] = process.env[key]
810
return acc
9-
}, {} as Record<string, string | undefined>)
10-
11+
}, {} as Record<string, string | undefined>) : {}
1112
return (
1213
<Html>
1314
<Head>
14-
<script
15-
id="env-vars"
16-
dangerouslySetInnerHTML={{
17-
__html: `window.__ENV = ${JSON.stringify(publicEnv)}`,
18-
}}
19-
/>
15+
{isDev ? (
16+
<script
17+
id="env-vars-dev"
18+
dangerouslySetInnerHTML={{
19+
__html: `window.__ENV = ${JSON.stringify(devEnv)}`,
20+
}}
21+
/>
22+
) : (
23+
<script src="/env-config.js" />
24+
)}
2025
<meta name="og:title" property="og:title" content="helpwave tasks" />
2126
<meta name="description" content="The first open-source team management platform for healthcare workers" />
2227
<meta property="og:description" content="The first open-source team management platform for healthcare workers" />

web/utils/config.ts

Lines changed: 27 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,44 @@
11
import { z } from 'zod'
22

33
export const publicEnvSchema = z.object({
4-
NODE_ENV: z.literal('production').or(z.literal('development')).default('production'),
5-
NEXT_PUBLIC_SHOW_STAGING_DISCLAIMER_MODAL: z.literal('true').or(z.literal('false')).optional(),
6-
NEXT_PUBLIC_FEATURES_FEED_URL: z.string().url().default('https://cdn.helpwave.de/feed.json'),
7-
NEXT_PUBLIC_IMPRINT_URL: z.string().url().default('https://cdn.helpwave.de/imprint.html'),
8-
NEXT_PUBLIC_PRIVACY_URL: z.string().url().default('https://cdn.helpwave.de/privacy.html'),
9-
NEXT_PUBLIC_GRAPHQL_ENDPOINT: z.string().url().default('http://localhost:8000/graphql'),
10-
NEXT_PUBLIC_ISSUER_URI: z.string().url().default('http://localhost:8080/realms/tasks'),
11-
NEXT_PUBLIC_CLIENT_ID: z.string().min(1).default('tasks-web'),
12-
NEXT_PUBLIC_REDIRECT_URI: z.string().min(1).default('http://localhost:3000/auth/callback'),
13-
NEXT_PUBLIC_POST_LOGOUT_REDIRECT_URI: z.string().min(1).default('http://localhost:3000/'),
4+
NODE_ENV: z.string().default('production'),
5+
RUNTIME_SHOW_STAGING_DISCLAIMER_MODAL: z.literal('true').or(z.literal('false')).optional(),
6+
RUNTIME_FEATURES_FEED_URL: z.string().url().default('https://cdn.helpwave.de/feed.json'),
7+
RUNTIME_IMPRINT_URL: z.string().url().default('https://cdn.helpwave.de/imprint.html'),
8+
RUNTIME_PRIVACY_URL: z.string().url().default('https://cdn.helpwave.de/privacy.html'),
9+
RUNTIME_GRAPHQL_ENDPOINT: z.string().url().default('http://localhost:8000/graphql'),
10+
RUNTIME_ISSUER_URI: z.string().url().default('http://localhost:8080/realms/tasks'),
11+
RUNTIME_CLIENT_ID: z.string().min(1).default('tasks-web'),
12+
RUNTIME_REDIRECT_URI: z.string().min(1).default('http://localhost:3000/auth/callback'),
13+
RUNTIME_POST_LOGOUT_REDIRECT_URI: z.string().min(1).default('http://localhost:3000/'),
1414
})
1515

1616
const configSchema = publicEnvSchema.transform(obj => ({
1717
env: obj.NODE_ENV,
18-
showStagingDisclaimerModal: obj.NEXT_PUBLIC_SHOW_STAGING_DISCLAIMER_MODAL === 'true',
19-
featuresFeedUrl: obj.NEXT_PUBLIC_FEATURES_FEED_URL,
20-
imprintUrl: obj.NEXT_PUBLIC_IMPRINT_URL,
21-
privacyUrl: obj.NEXT_PUBLIC_PRIVACY_URL,
22-
graphqlEndpoint: obj.NEXT_PUBLIC_GRAPHQL_ENDPOINT,
18+
showStagingDisclaimerModal: obj.RUNTIME_SHOW_STAGING_DISCLAIMER_MODAL === 'true',
19+
featuresFeedUrl: obj.RUNTIME_FEATURES_FEED_URL,
20+
imprintUrl: obj.RUNTIME_IMPRINT_URL,
21+
privacyUrl: obj.RUNTIME_PRIVACY_URL,
22+
graphqlEndpoint: obj.RUNTIME_GRAPHQL_ENDPOINT,
2323
auth: {
24-
issuer: obj.NEXT_PUBLIC_ISSUER_URI,
25-
clientId: obj.NEXT_PUBLIC_CLIENT_ID,
26-
redirect_uri: obj.NEXT_PUBLIC_REDIRECT_URI,
27-
post_logout_redirect_uri: obj.NEXT_PUBLIC_POST_LOGOUT_REDIRECT_URI,
24+
issuer: obj.RUNTIME_ISSUER_URI,
25+
clientId: obj.RUNTIME_CLIENT_ID,
26+
redirect_uri: obj.RUNTIME_REDIRECT_URI,
27+
post_logout_redirect_uri: obj.RUNTIME_POST_LOGOUT_REDIRECT_URI,
2828
}
2929
}))
3030

3131
const getConfig = () => {
32-
const localOverrides: Partial<z.output<typeof configSchema>> = {}
33-
34-
const source = (typeof window !== 'undefined' && window.__ENV)
35-
? window.__ENV
36-
: process.env
32+
if (typeof window !== 'undefined' && window.__ENV) {
33+
return configSchema.parse({
34+
...window.__ENV,
35+
NODE_ENV: process.env.NODE_ENV
36+
})
37+
}
3738

38-
const maybeConfig = configSchema.safeParse(source)
3939

40-
if (!maybeConfig.success) {
41-
throw new Error(`Invalid environment variables:\n${maybeConfig.error}`)
42-
} else {
43-
return Object.assign(maybeConfig.data, localOverrides)
44-
}
40+
const result = publicEnvSchema.safeParse(process.env)
41+
return configSchema.parse(result.data)
4542
}
4643

4744
export { getConfig }

0 commit comments

Comments
 (0)