In a backend apps or api (java, nodejs, php, python, etc) is best practice to use environment variables instead hardcoded in properties file because we can generate just one artifact for all of our environments(development, staging, production). Before its start, we only need to export the required variables and that's all.
But what happen in modern applications called : frontend rendering frameworks, spa, javascript apps which are developed with react, angular, vue, etc ?
- react, angular or vue are javascript frameworks to be loaded in browsers, not in the server like nodejs javascript
- Environment variables are not accessible from a browser. process.env offered by cra framework(react) is an "emulation" implemented with webpack in the deep of this framework. As a quick summary this framework reads the operative system variables and crete a javascript global variable (process.env) ready to use in your react files. Check this
- any variable used in these apps, are accessible with a simple browser inspection because these variables are hardcoded in the bowels of bundle.js, dist.js or whatever the build result is called. So no matter what you invent, if your javascript needs some variable, this must exist in the browser so it will be accessible by your users.
So if your react app(javascript) needs the classic api url to exchange information, you will need a variable in any part of your javascript. Check this to understand how can we inject variables in javascript apps.
Also remember that to deploy your builded javascript application could be deployed from basic tools (because the result are just static files: index.html, css, bundle.js, etc) to advanced servers:
(1)Basic approach
Before build process, just change the localhost:3000 to acme.api.com in some of your javascript files like, constants.js, setting.js, configuration.js, etc
- Advantage: easy and not external tools are required
- Disadvantage:
- devops is broken because a human is required in build process
- will need to repeat this process before any of your environments : dev, testing, staging, production, etc
- a new build process is required for any of your environments : dev, testing, staging, production, etc
(2)Medium Approach
Replace your constants.js to the classic .properties file, .env file or any kind of file in which we set all the variables that change when artifact is moved from one environment to another.
So you can have one properties file by environment close to your source code or outside of source code like your build server:
- src/resources/dev/app.properties or .env.dev
- src/resources/staging/app.properties or .env.staging
- src/resources/prodution/app.properties or .env.prodution
And finally with some trick you could switch between these files. package.json sample
"scripts": {
"build:dev": "export $(cat .env.dev | xargs) && react-scripts build",
"build:dev": "export $(cat .env.staging | xargs) && react-scripts build",
"build:dev": "export $(cat .env.dev | prodution) && react-scripts build"
}
Or play with the name of these files and some var like NODE_ENVIRONMENT. Check these links to view more examples:
This approach is similar to your current workaround. Check this: https://dev.to/rishikeshvedpathak/react-environment-specific-builds-using-env-with-cra-and-env-cmd-296b
Also check Angular cli limitation: Every environment requires a separate build
(3) Advanced approach
What if your javascript app at the first invocation, get or retrieve the configurations from a kind of rest endpoint?
- Advantage:
- easy
- one build for all your envinronments
- open the posibility to hot reload of configurations in the javascript apps. Something like: Hey, user! refresh your web to view the new season effect.
- devops process is happy
- Disadvantage:
- a new platform or a simple endpoint is required. This is in charge of give us the variables
- intermediate javascript knoledge is required to perform this ajax invocation at the first user invocation
On my apps I called /settings to this endpoint. This returns a json response with several variables like:
- api base urls
- some quotes to home page
- background colors
- any configuration parameters required by the frontend app
- etc
Take a look to my server: https://github.com/utec/geofrontend-server. It was designed for requirements exactly like yours. I think the readme is good, but contact me with an issue if you need some help. As a summary if you want to use this nodejs server for your app, the steps will be:
- create one properties file with environment vars
- add one dependency to your react app package.json
- just run