version: "3"
services:
web:
# replace username/repo:tag with your name and image details
image: user1/webapp:latest
volumes:
- ./local-db:/go/src/webapp/local-db
environment:
- REACT_APP_ENDPOINT=http://api.com
deploy:
replicas: 5
resources:
limits:
cpus: "0.1"
memory: 50M
restart_policy:
condition: on-failure
ports:
- "8080:8080"
networks:
- webnet
networks:
webnet:
webapp
is server that serves a create-react-app but when I run
console.log("process.env.REACT_APP_ENDPOINT")
console.log(process.env.REACT_APP_ENDPOINT)
according to https://daveceddia.com/multiple-environments-with-react/ I should be able to access the environment variables. I run the docker-compose using
docker swarm init
docker stack deploy -c ~/webapp/docker-compose.yml webapp
The console log prints undefined
but if I run the server serving create-react-app on my local machine without docker, the frontend properly prints the environment variable.
I noticed a lot of people struggle with this, and particularly how to pass ENV vars instead of conditional scripting in Dockerfile, so I provided a simplified Github repo tutorial:
- https://github.com/mikesparr/tutorial-react-docker
Background via a public article on LinkedIn articles if you care to read:
- https://www.linkedin.com/pulse/dockerizing-your-react-app-mike-sparr/
In short, you need your Dockerfile CMD
to run a script that performs the build
and the server start
steps so the app can use the runtime container configs.
Also, you need to prefix your ENV vars with REACT_APP_<yourvarname>
and in your app, reference them using process.env.REACT_APP_SOMEVAR
.
Create-react-app prefers to have a .env file in order to embed your env vars into the build.
Obviously it's not a good practice to version control a .env file, the create-react-app official documentation go against the 12-factor-app philosophy.
So let's use a clean solution ! The most simple way is to create a .env file on the fly into the Dockerfile build environment :
For this create a simple script create-env-file.sh
:
touch .env
for envvar in "$@"
do
echo "$envvar" >> .env
done
It will copy every args you pass it to a new .env file
Then call it before RUN npm run build
in your Dockerfile :
FROM node:14-alpine
WORKDIR /app
COPY src/ ./src/
COPY public/ ./public/
COPY pack*.json ./
COPY tsconfig.json .
COPY create-env-file.sh ./create-env-file.sh
RUN npm i
# Add as many arguments as you want to pass environment variables
# and use an ARG command for each one, so Dockerfile context will grab it from --build-arg
ARG REACT_APP_ENDPOINT
RUN sh create-env-file.sh REACT_APP_ENDPOINT=$REACT_APP_ENDPOINT
# If you want to debug the .env file, uncomment the following line
# CMD ["cat", ".env"]
RUN npm run build
RUN npm i -g serve
EXPOSE 5000
CMD ["serve", "-s", "build"]
Then use --build-arg
to pass your env vars to the docker build command :
docker build --build-arg REACT_APP_ENDPOINT=http://api.com -t front-server .
You have to reference each passed build arg with an ARG command because docker build consider build args as arguments and NOT environment variables. See here
So your docker-compose.yml would look like this :
version: "3"
services:
web:
build:
context: .
args:
REACT_APP_ENDPOINT=http://api.com
image: user1/webapp:latest
volumes:
- ./local-db:/go/src/webapp/local-db
deploy:
replicas: 5
resources:
limits:
cpus: "0.1"
memory: 50M
restart_policy:
condition: on-failure
ports:
- "8080:8080"
networks:
- webnet
networks:
webnet:
Use --build
with docker-compose up :
docker-compose up --build
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With