Introduction

In the fast-paced world of web and mobile app development, flexibility and adaptability are key. This is particularly true when it comes to configuring user interfaces to connect with various backend services across different environments such as Test, Development, and Production. In this blog post, we'll explore the challenges and solutions we encountered while working with ReactJS to achieve a dynamic backend URL configuration.

The Challenge of Hardcoded URLs

Our project initially employed hardcoded backend URLs within the codebase. This approach was full of challenges:

  • Any change in the backend URL necessitated a manual code update and redeployment, which was time-consuming and error-prone.

  • Deployment scenarios like Kubernetes, where backend URLs are not predetermined, demanded a more dynamic configuration method.

A Step Towards Flexibility: Config.js

To overcome these hurdles, we proposed defining all backend URLs in a Config.js file within the React project. By using variables from Config.js throughout the code, we could build and deploy the project using Nginx or Tomcat, thus centralizing URL management and simplifying changes.

Pros:

  • Centralized URL management reduces boilerplate code and simplifies updates.

Cons:

  • Separate builds and deployments are required for each environment (Test, Development, Production), each needing a unique Config.js.

window._env_ = {

REACT_APP_URL:"http://localhost",

REACT_APP_API_URL: "default",

REACT_APP_VEHICLE_IMAGE_URL: "default",

REACT_APP_NAME: " default",

}


Streamlining Deployment: Environment-Specific Hardcoding

We refined our approach by building the React project once with default values in Config.js. During deployment, we would create copies of the build and modify the Config.js file in each to include environment-specific backend URLs.

Cons:

  • This method still involved manual editing of Config.js, introducing the risk of errors and additional deployment steps.

The Docker-Based Solution

Our next iteration utilized Docker for deploying the build to Nginx or Tomcat. We included a script in the Dockerfile that used “echo” statements (with parameter name hardcoded and value as a placeholder), allowing for dynamic URL configuration during the Docker Compose process. Once the image is created, the actual values can be passed during the container startup.

Cons:

  • We encountered issues with Docker not correctly reading the script file during the container startup, leading to inconsistencies in URL configuration.

The Final Approach: Embedded Scripting

Continuing with Docker for deployment, we embedded the necessary script directly within the Docker image. This ensured that dynamic values and runtime URL configurations were properly set, addressing the previous issues and streamlining the deployment process.

# Use the official NGINX base image
FROM nginx: latest

# Copy your React build files to the NGINX static content folder
COPY application/build/ /usr/share/nginx/html/build

ENV BACKEND_URL 'default'
ENV APP_NAME 'default'

RUN touch /usr/share/nginx/scripts/set_env.sh
RUN echo "#!/bin/bash\n\
\n\
echo \$1\n\
echo \$2\n\
# Check if REACT_APP_URL is provided as an environment variable\n\
if [ -z \$1 ]\n\
then\n\
echo \"Error: BACKEND_URL environment variable not set.\"\n\
exit 1 \n\
fi \n\
\n\
if [ -z \$2 ] \n\
then \n\
echo \"Error: APP_NAME environment variable not set.\" \n\
exit 1 \n\
fi \n\
echo \"window._env_ = { REACT_APP_URL: '\$1', REACT_APP_API_URL: 'default', REACT_APP_VEHICLE_IMAGE_URL: 'default', REACT_APP_NAME: '\$2' };\" > /usr/share/nginx/html/build/config.js \n\
" > /usr/share/nginx/scripts/set_env.sh

# Make the script executable
RUN chmod +x /usr/share/nginx/scripts/set_env.sh

# Start NGINX
CMD ["/bin/sh", "-c", "/usr/share/nginx/scripts/set_env.sh ${BACKEND_URL} ${APP_NAME}} && nginx -g 'daemon off;'"]


Conclusion

By adopting this final solution, we have created a more reliable and automated configuration process for environment-specific URLs. This reduces the risk of manual errors and ensures a smooth and efficient deployment workflow, allowing our React UI to dynamically connect with various backend services.

References:

https://react.dev/blog

https://stackoverflow.com/

https://www.baeldung.com/