diff --git a/front/package.json b/front/package.json
index 21cd338be..8bd4ec959 100644
--- a/front/package.json
+++ b/front/package.json
@@ -66,7 +66,8 @@
},
"scripts": {
"start": "PORT=3001 craco start --max-warnings=0",
- "build": "craco build",
+ "build:inject-runtime-env": "./scripts/inject-runtime-env.sh",
+ "build": "craco build && yarn build:inject-runtime-env",
"test": "craco test",
"coverage": "craco test --coverage .",
"lint": "eslint src --max-warnings=0",
diff --git a/front/public/env-config.js b/front/public/env-config.js
new file mode 100644
index 000000000..20254cd25
--- /dev/null
+++ b/front/public/env-config.js
@@ -0,0 +1,3 @@
+window._env_ = {
+ // This file should stay empty. It will be overwritten by the build process.
+}
diff --git a/front/public/index.html b/front/public/index.html
index 9578c1eca..f2d2be21b 100644
--- a/front/public/index.html
+++ b/front/public/index.html
@@ -36,6 +36,7 @@
/>
Twenty
+
diff --git a/front/scripts/inject-runtime-env.sh b/front/scripts/inject-runtime-env.sh
new file mode 100755
index 000000000..d4281004b
--- /dev/null
+++ b/front/scripts/inject-runtime-env.sh
@@ -0,0 +1,11 @@
+echo "Generating env-config.js file from runtime environment variables..."
+
+BASE_FILENAME="build/env-config.js"
+mkdir -p build
+rm -rf "./$BASE_FILENAME"
+
+{
+ echo "window._env_ = {"
+ echo " REACT_APP_SERVER_BASE_URL: \"$REACT_APP_SERVER_BASE_URL\","
+ echo "}"
+} > "./$BASE_FILENAME"
\ No newline at end of file
diff --git a/front/src/config/index.ts b/front/src/config/index.ts
new file mode 100644
index 000000000..48d0908f2
--- /dev/null
+++ b/front/src/config/index.ts
@@ -0,0 +1,10 @@
+declare global {
+ interface Window {
+ _env_?: Record;
+ }
+}
+
+export const REACT_APP_SERVER_BASE_URL =
+ window._env_?.REACT_APP_SERVER_BASE_URL ||
+ process.env.REACT_APP_SERVER_BASE_URL ||
+ 'http://localhost:3000';
diff --git a/front/src/modules/apollo/hooks/useApolloFactory.ts b/front/src/modules/apollo/hooks/useApolloFactory.ts
index 9f996cf60..e2d66eb0e 100644
--- a/front/src/modules/apollo/hooks/useApolloFactory.ts
+++ b/front/src/modules/apollo/hooks/useApolloFactory.ts
@@ -6,6 +6,7 @@ import { useRecoilState } from 'recoil';
import { tokenPairState } from '@/auth/states/tokenPairState';
import { isDebugModeState } from '@/client-config/states/isDebugModeState';
import { AppPath } from '@/types/AppPath';
+import { REACT_APP_SERVER_BASE_URL } from '~/config';
import { ActivityTarget } from '~/generated/graphql';
import { useIsMatchingLocation } from '~/hooks/useIsMatchingLocation';
import { useUpdateEffect } from '~/hooks/useUpdateEffect';
@@ -23,7 +24,7 @@ export const useApolloFactory = () => {
const apolloClient = useMemo(() => {
apolloRef.current = new ApolloFactory({
- uri: `${process.env.REACT_APP_SERVER_BASE_URL}/graphql`,
+ uri: `${REACT_APP_SERVER_BASE_URL}/graphql`,
cache: new InMemoryCache({
typePolicies: {
Activity: {
diff --git a/front/src/modules/auth/hooks/useAuth.ts b/front/src/modules/auth/hooks/useAuth.ts
index c41282fe7..071bdd0c2 100644
--- a/front/src/modules/auth/hooks/useAuth.ts
+++ b/front/src/modules/auth/hooks/useAuth.ts
@@ -6,6 +6,7 @@ import {
useRecoilState,
} from 'recoil';
+import { REACT_APP_SERVER_BASE_URL } from '~/config';
import {
useChallengeMutation,
useCheckUserExistsLazyQuery,
@@ -136,8 +137,7 @@ export const useAuth = () => {
const handleGoogleLogin = useCallback((workspaceInviteHash?: string) => {
const authServerUrl =
- process.env.REACT_APP_SERVER_AUTH_URL ??
- process.env.REACT_APP_SERVER_BASE_URL + '/auth';
+ REACT_APP_SERVER_BASE_URL ?? REACT_APP_SERVER_BASE_URL + '/auth';
window.location.href =
`${authServerUrl}/google/${
workspaceInviteHash ? '?inviteHash=' + workspaceInviteHash : ''
diff --git a/front/src/modules/metadata/components/ApolloMetadataClientProvider.tsx b/front/src/modules/metadata/components/ApolloMetadataClientProvider.tsx
index 67371da99..b3eb9db9b 100644
--- a/front/src/modules/metadata/components/ApolloMetadataClientProvider.tsx
+++ b/front/src/modules/metadata/components/ApolloMetadataClientProvider.tsx
@@ -4,6 +4,7 @@ import { ApolloClient, InMemoryCache } from '@apollo/client';
import { useRecoilState } from 'recoil';
import { tokenPairState } from '@/auth/states/tokenPairState';
+import { REACT_APP_SERVER_BASE_URL } from '~/config';
import { ApolloMetadataClientContext } from '../context/ApolloClientMetadataContext';
@@ -17,7 +18,7 @@ export const ApolloMetadataClientProvider = ({
const apolloMetadataClient = useMemo(() => {
if (tokenPair?.accessToken.token) {
return new ApolloClient({
- uri: `${process.env.REACT_APP_SERVER_BASE_URL}/metadata`,
+ uri: `${REACT_APP_SERVER_BASE_URL}/metadata`,
cache: new InMemoryCache(),
headers: {
Authorization: `Bearer ${tokenPair.accessToken.token}`,
diff --git a/front/src/modules/users/utils/getProfilePictureAbsoluteURI.ts b/front/src/modules/users/utils/getProfilePictureAbsoluteURI.ts
index 77350d114..ccd502d18 100644
--- a/front/src/modules/users/utils/getProfilePictureAbsoluteURI.ts
+++ b/front/src/modules/users/utils/getProfilePictureAbsoluteURI.ts
@@ -1,3 +1,5 @@
+import { REACT_APP_SERVER_BASE_URL } from '~/config';
+
export const getImageAbsoluteURIOrBase64 = (imageUrl?: string | null) => {
if (!imageUrl) {
return null;
@@ -12,8 +14,7 @@ export const getImageAbsoluteURIOrBase64 = (imageUrl?: string | null) => {
}
const serverFilesUrl =
- process.env.REACT_APP_SERVER_FILES_URL ??
- process.env.REACT_APP_SERVER_BASE_URL + '/files';
+ REACT_APP_SERVER_BASE_URL ?? REACT_APP_SERVER_BASE_URL + '/files';
return `${serverFilesUrl}/${imageUrl}`;
};
diff --git a/infra/prod/front/Dockerfile b/infra/prod/front/Dockerfile
index 88c156bc6..2b6c3e798 100644
--- a/infra/prod/front/Dockerfile
+++ b/infra/prod/front/Dockerfile
@@ -1,6 +1,5 @@
FROM node:18.16.0-alpine as build
-
ARG REACT_APP_SERVER_BASE_URL
ARG REACT_APP_SERVER_AUTH_URL
ARG REACT_APP_SERVER_FILES_URL
@@ -18,10 +17,13 @@ COPY ./infra/prod/front/serve.json ./build
FROM node:18.16.0-alpine as front
WORKDIR /app/front
+
COPY --from=build /app/front/build ./build
+COPY ./front/scripts/inject-runtime-env.sh /app/front/scripts/inject-runtime-env.sh
RUN yarn global add serve
+
LABEL org.opencontainers.image.source=https://github.com/twentyhq/twenty
LABEL org.opencontainers.image.description="This image provides a consistent and reproducible environment for the frontend."
-CMD ["serve", "build"]
+CMD ["/bin/sh", "-c", "/app/front/scripts/inject-runtime-env.sh && serve build"]
diff --git a/infra/prod/server/Dockerfile b/infra/prod/server/Dockerfile
index 2e795682a..f7fba86aa 100644
--- a/infra/prod/server/Dockerfile
+++ b/infra/prod/server/Dockerfile
@@ -1,4 +1,4 @@
-FROM node:18.16.0-alpine as server
+FROM node:18.16.0-alpine as build
WORKDIR /app/server
COPY ./server/package.json ./
@@ -11,6 +11,12 @@ RUN npx prisma generate
RUN yarn build
+FROM node:18.16.0-alpine as server
+
+COPY --from=build /app/server/dist ./dist
+
+WORKDIR /app/server
+
LABEL org.opencontainers.image.source=https://github.com/twentyhq/twenty
LABEL org.opencontainers.image.description="This image provides a consistent and reproducible environment for the backend, ensuring it deploys faster and runs the same way regardless of the deployment environment."
diff --git a/render.yaml b/render.yaml
index 4411c52df..e028d983b 100644
--- a/render.yaml
+++ b/render.yaml
@@ -14,7 +14,7 @@ services:
name: server
env: docker
dockerfilePath: ./infra/prod/server/Dockerfile
- dockerCommand: "sh -c yarn prisma:migrate && yarn database:setup && node dist/src/main"
+ dockerCommand: "sh -c ./scripts/compute-database-url.sh && yarn prisma:migrate && yarn database:setup && node dist/src/main"
autoDeploy: false
envVars:
- key: FRONT_BASE_URL
@@ -38,8 +38,6 @@ services:
name: twenty_postgres
type: pserv
property: port
- - key: PG_DATABASE_URL
- value: postgres://twenty:twenty@twenty-postgres:5432/default?connection_limit=1
disk:
name: twenty-disk
mountPath: /.local-storage
diff --git a/server/scripts/compute-database-url.sh b/server/scripts/compute-database-url.sh
new file mode 100755
index 000000000..dad7d8521
--- /dev/null
+++ b/server/scripts/compute-database-url.sh
@@ -0,0 +1,2 @@
+#!/bin/sh
+export PG_DATABASE_URL=postgres://twenty:twenty@$PG_DATABASE_HOST:5432/default
\ No newline at end of file
diff --git a/server/scripts/run-integration.sh b/server/scripts/run-integration.sh
index fc30b598b..3673ab813 100755
--- a/server/scripts/run-integration.sh
+++ b/server/scripts/run-integration.sh
@@ -1,5 +1,5 @@
#!/usr/bin/env bash
-# src/run-integration.sh
+# scripts/run-integration.sh
DIR="$(cd "$(dirname "$0")" && pwd)"
source $DIR/set-env-test.sh
diff --git a/server/scripts/set-env-test.sh b/server/scripts/set-env-test.sh
index 8eb4eee9d..98e7ac7c9 100755
--- a/server/scripts/set-env-test.sh
+++ b/server/scripts/set-env-test.sh
@@ -1,5 +1,5 @@
#!/usr/bin/env bash
-# scripts/setenv.sh
+# scripts/set-env-test.sh
# Get script's directory
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"