How can I change the environment variable in my dockerized front-end React application without rebuilding the Docker image? What if I simply need to change the API URL environment variable?
Docker React GCP
These might be the questions you face during your developing journey.
When building a container for modern apps (for example, in React, Angular or Vue.js), you have to be able to change configuration settings based on where the container runs. One of the most common modifications would be the API URL depending on the stage of the front-end application.
In our case we had a legacy dockerized Front-End React App on Google Cloud Run node. This app was sending the API requests to the API gateway URL.
What we needed was to modify this URL as environment variable in Front-End container and simply redeploy the container without rebuilding. It was important for us as building that Front-End docker container was take more time than normally due to some technical limitations we had in the legacy React app.
Where the problem comes from
Let’s take a look how most of the Docker containers for React Apps served through Nginx are built (I’ve removed some steps from the code for simplicity):
FROM node:16-alpine as builder
WORKDIR /var/www/clientapp\_frontend
COPY package.json .
RUN npm install
COPY . .
_\# two lines below to make FLASK\_API\_URL settable via --build-arg in docker build command_
ARG BUILDTIME\_FLASK\_API\_URL='some\_fallback\_default\_URL'
ENV FLASK\_API\_URL=$BUILDTIME\_FLASK\_API
RUN npm run build_\# taking the dist build from the previous builder container and using it in a nginx container_
FROM nginx:1.17-alpine
COPY — from=builder /var/www/clientapp\_frontend/build/ /usr/share/nginx/html
COPY — from=builder /var/www/clientapp\_frontend/nginx\_entrypoint.sh ./nginx\_entrypoint.sh
EXPOSE $FRONTEND\_PORT
ENTRYPOINT /bin/sh -x ./nginx\_entrypoint.sh && nginx -g ‘daemon off;’
As you can see there’s an environment variable FLASK_API_URL provided during building. However, what many articles about building a React App in Nginx with Docker miss mentioning is that it’s not possible to override such environment variable at runtime since its runtime is the client’s browser. In other words, this FLAKS_API_URL value gets hardcoded in the JS bundle.
Solution
There is a possibility to inject environment variables at the moment when the container starts. These environment variables are to be written in some JS file and served by Nginx with a <script>
tag inside index.html
Check my nginx_entrypoint.sh file in my GitHub repository for the full code to see how I inject environment variables at runtime generating JS script env-config.js and inserting it to index.html with bash.
- FLASK_API_URL env varianle is read and placed into .env file.
env\_content=’FLASK\_API\_URL=${FLASK\_API\_URL}’printf “$env\_content” > /usr/share/nginx/html/.env
- Then all environment variables are read from .env file and saved in JS script env-config.js
echo “window.\_env\_ = {“ > /usr/share/nginx/html/env-config.jsawk -F ‘=’ ‘{ print $1 “: \\”” (ENVIRON\[$1\] ? ENVIRON\[$1\] : $2) “\\”,” }’ /usr/share/nginx/html/.env >> /usr/share/nginx/html/env-config.jsecho “}” >> /usr/share/nginx/html/env-config.js
- At the end of the file this JS script is placed inside index.html, so the React App can digest these environment variables.
sed -i.bak ‘s~<body\[^>\]\*>~&<script src=”env-config.js”></script>~’ /usr/share/nginx/html/index.html
See the full code of it my GitHub repository
https://github.com/iskandre/dockerized-react-env-variables
GitHub - iskandre/dockerized-react-env-variables: A simple example demonstrating a Dockerfile for React app served by Nginx and how to inject runtime env variables to React when starting the docker container
Thanks for reading.
I hope this will be a help and feel free to share your thoughts, suggestions or ask any questions.