Managing Multi-Environment Configurations For React Applications with Tanzu

Written by camposer | Published 2021/01/01
Tech Story Tags: react | javascript | cloud-foundry | tanzu | nginx | tanzu-application-service | create-react-app | programming | web-monetization

TLDRvia the TL;DR App

Many SPA React Apps are created using the NPM Create React App (CRA) package. It creates apps without build configuration and that is more than enough for many use cases. A simple google search would give you a good idea about the pros and cons of this approach. Some interesting articles: one, two and three.
One of the main advantages of CRA is how easy it allows you to build apps as static/minified files. Once you have a set of static files, you could use any HTTP Server for serving the app, e.g. apache, nginx, S3.
What I just commented above sounds great. However, because everything is static, adding dynamism to the app can be a challenge. The model assumes that any dynamism comes from outside, usually an API. That works well for most cases, but sounds like an overkill for config files.
A common challenge to face is when you need to specify different backend(s) base URI(s) depending on the environment. For example: BACKEND1_BASE_URL could be https://mybackend-dev/api/v1 or https://mybackend/api/v1
You could overcome the challenge mentioned above using Custom Environment Variables and deploy the app to Tanzu Application Service (TAS) using the Static Buildpack, super easy! Take a look at the following bash snippet.
However, one important drawback of the commented approach is when you need to maintain/store artifacts per build. You’d end up with a nightmare of different versions per environment that can significantly increase your inventory management complexity. Just imagine: myapp-dev-v1.0.zip, myapp-sit-v1.0.zip, myapp-uat-v1.0.zip and myapp-prod-v1.0.zip!
There are other possibilities you could use for avoiding versioning hell. Some related to custom hostname resolutions or proxy intermediaries (e.g. reverse proxy). In this post I want to focus on a proxy intermediary approach that relies on different files for each environment.
In order to better explain the approach, I’ve decided to code a simple React App and deploy it to TAS. Why TAS? Because I truly believe there is no easier way to deploy/maintain your app! You have all the Cloud Foundry goodies plus the tiles and accumulated app development knowledge from Pivotal and VMware.

The approach

You can find the app live here and the source code here. Excuse the poor CSS and UI taste! I just want to demo how the config files can be changed via environment variables. If you run the app locally, you’d see: Welcome, Dev! and if you run it on TAS: Welcome, Prod!.
Following the detailed explanation of all the changes introduced to the React App commented above, created initially with: npx create-react-app
Configure env files
<script src="%PUBLIC_URL%/config.js"></script>
And then add the config files for running the application locally (config.js) and for different environments (e.g. prod.js). When you run the application locally (npm start) it just uses the config.js file.
Configure NGINX
I’m using the NGINX Buildpack instead of the Static Buildpack because the approach requires changes to the nginx.conf file.
You could find the full nginx.conf here, specially important for this explanation the following lines:
…
location /config.js {
  set $config_file "{{env "CONFIG_FILE"}}";
  try_files /$config_file =500;
}
…
NGINX would serve the config file depending on the value of the environment variable CONFIG_FILE, for example: prod.js. See the manifest.yml
In order to deploy the app, the easiest part if you’re using TAS, you’d run: cf push -f manifest.yml

Final words

Hope this post helps! At least, I expect it triggers some thoughts :-)
Some benefits:
Eliminates multiple artifacts per environment. Reduces ops complexityRespects the Separation of Concerns principle. Frontend config stays at the frontend.Eliminates endpoints for getting App Config.
Some challenges:
You need HTTP Server config! If you just want to use S3 or similar, then it wouldn’t be feasible.A file named config for the local configuration might cause confusion.
I still don’t have a final word about “the way to go”. I guess it depends. In any case, certainly this approach could keep your app simple when handling multiple environments, especially if you need to create versions and don’t want to generate several files per environment.

Written by camposer | Family man and tech geek - passionate about Software & Data Engineering, and Entrepreneurship
Published by HackerNoon on 2021/01/01