When developing a React application, you might need to deal with different environments. Based on my experience, you should consider at least the following three environments:
- Development
- Staging
- Production
Before deploying your React app to one of the last two environments, you need to build it. This is usually achieved by running a command aimed at creating a deployable build saved in your project’s build
folder.
Such a method has a tremendous downside. For example, you cannot launch many build commands in parallel. In fact, they all depend on the same folder. As a consequence, when dealing with several environments, this may be a bottleneck.
Plus, since every environment shares the same build folder, it is not intuitive to figure out what the target environment of your last build was. This can lead to errors as well.
Let’s see how to avoid this by correctly building a multi-environment app in React.
1. Installing the Required Dependencies
First of all, you need to add react-app-rewired
and env-cmd
to your project’s dependencies. You can install both with the following command:
npm install react-app-rewired env-cmd --save
To be able to specify a custom build path, you have to change your webpack configuration. If you created your app by using create-react-app
, you might be forced to eject your project — and this should be avoided if not strictly required.
This is where react-app-rewired
comes into play!
Note: If your project already uses react-app-rewired
, you can skip the following two steps.
Thanks to it, you can easily tweak the create-react-app
webpack config. In order to make everything work, you need to follow the next two steps:
- Create a valid
config-overrides.js
file in your root directory. - Change the existing references from
react-scripts
toreact-app-rewired
in thescripts
section of yourpackage.json
file.
Before:
{ "scripts": { "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject" } }
After:
{ "scripts": { "start": "react-app-rewired start", "build": "react-app-rewired build", "test": "react-app-rewired test", "eject": "react-app-rewired eject" } }
You have just rewired your React app and are now ready to define environment-based build paths.
Plus, react-app-rewired
allows you to achieve other fantastic goals. For example, defining absolute path aliases to make your imports refactor-friendly.
2. Defining the Environment Files
Now, it is time to define a .env
file for each of your environments. Such a file should contain whatever variable whose value depends on the current environment.
Let’s define two .env
files where we’ll put the build path depending on the current environment.
The staging .env.staging
env file:
REACT_APP_BUILD_PATH=build-staging # ... (other environment variables)
The production .env.production
env file:
REACT_APP_BUILD_PATH=build # ... (other environment variables)
Note: As stated in the Create React App documentation, every environment variable must start with REACT_APP_
.
3. Using the Environment Variable
To read the build path from the environment file and use it as a base path for your builds, define a config-overrides.js
file as follows:
const path = require('path'); module.exports = { webpack: function(config, env) { // your webpack configs return config; }, // the paths config used when your React app is builded paths: function(paths, env) { // reading the build path from the selected .env file const buildPath = process.env.REACT_APP_BUILD_PATH // defining "build" as a fallback path paths.appBuild = path.resolve(__dirname, buildPath ? buildPath : "build"); return paths; } }
As you can see, I ensured that the appBuild
variable has a valid fallback value. This is extremely important. An empty, null
, or undefined
string could cause the build process to go terribly wrong, potentially affecting your entire code base.
Then, you should define a build command for each of your .env
files. By employing env-cmd
, you can pass a custom .env
file to your build command by using the -f
flag.
Make sure the scripts
section of your package.json
file contains the following two lines:
"build": "react-app-rewired build", "build:staging": "env-cmd -f .env.staging npm run build"
By default, the env.production
file will be used, so you do not need to specify it in the first command.
Now, you can create an environment-based build with the following commands.
For the staging environment:
npm run build:staging
For the production environment:
npm run build
The builds will be placed in the target path defined in the REACT_APP_BUILD_PATH
environment variable. If you followed the example, your staging builds will be created in the build-staging
folder, while your production builds in the build
folder.
Et voilà! Each of your environments now has a dedicated build folder.
Conclusion
Today, we looked at how to define a build folder for each environment of your React app. This way, you can launch different build commands in parallel and make sure that all of them have their own dedicated target folder. As I have just shown, this can easily be achieved by using react-app-rewire
and env-cmd
. Plus, such an approach can easily be extended to any number of environments.
Thanks for reading! I hope that you found this article helpful.