Streamlining React App Deployments: Overcoming Docker Build Args Limitations with `env-config.js`
Tags: react, docker, kubernates, devops
Published: 2024-04-03 12:59:23

When deploying React applications or any javascript based frontend applications such as Angular, Vuejs etc across various environments like development, staging, and production, developers often face a common challenge with Docker: the limitations of build arguments (`--build-arg`). Build arguments are frequently used to pass environment-specific configurations to a Docker image at build time. However, this approach hardcodes the values into the image, reducing flexibility and requiring separate builds for each environment. This article explores an alternative strategy using `env-config.js`, enhancing the reusability and flexibility of Docker images across different environments.

### **Understanding the Problem with Docker Build Args**

Docker's build arguments allow you to pass configuration during the image build process. For instance:

```dockerfile
ARG REACT_APP_API_URL
ENV REACT_APP_API_URL=$REACT_APP_API_URL
```

While this method is effective for injecting environment variables into the Docker image, it has a significant drawback. The variables become hardcoded into the image. As a result, the same image cannot be reused across different environments (dev, staging, prod) without rebuilding it for each one. This leads to a lack of flexibility and increased complexity in your CI/CD pipeline.

### **The Solution: `env-config.js`**

A more flexible approach involves using a JavaScript file, `env-config.js`, generated dynamically at runtime. This file is created using a bash script and loaded before your React application starts:

```bash
#!/bin/bash
echo "window._env_ = {" > /var/www/html/env-config.js
echo "  REACT_APP_API_URL: \"${REACT_APP_API_URL}\"" >> /var/www/html/env-config.js
echo "}" >> /var/www/html/env-config.js
```

With this setup, the environment variables are not hardcoded into the Docker image. Instead, they are injected at runtime, allowing the same image to be used across multiple environments.

### **Integrating `env-config.js` with Docker**

Here's how to configure the Dockerfile for this approach:

```dockerfile
# Build stage for React app
FROM node:latest as build
WORKDIR /app
COPY package.json ./
COPY yarn.lock ./
RUN yarn install
COPY . ./
RUN yarn build

# Nginx stage
FROM nginx:alpine
COPY --from=build /app/build /var/www/html
COPY env-to-js.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/env-to-js.sh
CMD ["/bin/sh", "-c", "/usr/local/bin/env-to-js.sh && nginx -g 'daemon off;'"]
```

This Dockerfile builds the React app and sets up Nginx to serve it. The critical addition is the `env-to-js.sh` script that generates `env-config.js` at container startup, injecting the current environment's variables.

### **Accessing Environment Variables in React**

In your React application, access these variables from the global `window` object:

```javascript
const apiUrl = window._env_.REACT_APP_API_URL || 'default-api-url';
```

### **Security Considerations**

It’s important to note that any information in env-config.js is publicly visible. Be cautious not to include sensitive data like private API keys, secrets etc. Treat `env-config.js` as a publicly accessible resource.

### **Conclusion: Enhanced Flexibility and Reusability**

By adopting the `env-config.js` strategy in your Dockerized React application, you achieve significant flexibility. This approach allows you to use the same Docker image across various environments without the need for separate builds, simplifying your deployment process and enhancing maintainability.