أحمد

Create React App: Runtime vs Buildtime Environment Variables

8/13/2019 - 7 min read

This post will show you how I migrate create-react-app custom environment variables from buildtime to be configurable at runtime. According to create-react-app docs, we can not embed environement variables during runtime. so defining them with the prefix REACT_APP_ will expose them only in build-time where you can access them by process.env.REACT_APP_KEY

Note: I will use these aliases throughout the rest of the article:

  • env vars instead of environment variables
  • env/s instead of enviroment/s

Initializing Environment Variables in Buildtime

To define env vars in buildtime, just put your own env vars keys into the .env file located in your home path, and prefixed by REACT_APP_. The env vars in this file will be exposed to your JS code in the development environment only. There are more configurable ways to define env vars in test, production envs, and even override all the three envs locally on your machine as described in create-react-app docs as the following:

  • test env > add the env vars in .env.test
  • prodcution env > add the env vars in .env.production
  • locally-test-override env > add env vars in .env.local.test
  • locally-production-override > add env vars in .env.local.production
  • locally-development-override > add env vars in .env.local.development

There is something to be considered; .env files have precedence rules based on which npm/yarn command you will run as the following:

  • yarn/npm start: .env.development.local, .env.development, .env.local, .env
  • yarn/npm build: .env.production.local, .env.prodcution, .env.local, .env
  • yarn/npm test: .env.test.local, .env.test, .env

when the precedence is from the left to the right.

Note: .env.local is missing from yarn/npm test and don't know why! but it is mentioned in create-react-app docs!

A final example will be a .env file with env vars keys and values like this:

REACT_APP_KEY = <some-value>;

Migrate to Runtime Environment Variables

This is a hack solution because the definition of env vars in browsers does not even exist. It is something like a fake abstraction as mentioned here. We will keep our .env file only with the default development env vars as it is our main concern.

How this will be done?

I extract the env vars in .env file into a new javascript config file using a simple bash script as below imported from here

#!/bin/bash
set -e
# Define env-config path
env_config_path=./env-config.js
# Recreate config file
rm -rf $env_config_path
touch $env_config_path
# Add assignment
echo "window._env_ = {" >> $env_config_path
# Read each line in .env file
# Each line represents key=value pairs
while read -r line || [[ -n "$line" ]];
do
# Split env variables by character `=`
if printf '%s\n' "$line" | grep -q -e '='; then
varname=$(printf '%s\n' "$line" | sed -e 's/=.*//')
varvalue=$(printf '%s\n' "$line" | sed -e 's/^[^=]*=//')
fi
# Read value of current variable if exists as Environment variable
value=$(printf '%s\n' "${!varname}")
# Otherwise use value from .env file
[[ -z $value ]] && value=${varvalue}
# Append configuration property to JS file
echo " $varname: \"$value\"," >> $env_config_path
done < .env
echo "}" >> $env_config_path

This will create as env-config.js file that you will need to embed like below:

<script src="%PUBLIC_URL%/env-config.js"></script>

into your public/index.html.

And, this is how the file will look like:

window.__env__ = {
REACT_APP_KEY: value,
};

Putting All Together

To get all of these running in development, you will need to:

• update yarn/npm start command to

./env.sh && ./env.sh && cp env-config.js ./public/ && react-scripts start

• replace all

process.env.REACT_APP_KEY;

by

window.__env__.REACT_APP_KEY;

Setup Tests Environment Variables

Doing all of the above will not guarantee running your test suites correctly, actually, you will see an error that can't read property REACT_APP_KEY of undefined. This is because __env__ is not exposed in the test environment which by the way is a build-time process. There is a hack solution for this problem which is reusing .env file to assign all the values from it to __env__ into your setupTests.js like below:

window.__env__ = {
REACT_APP_KEY: process.env.REACT_APP_KEY,
};
Resumeأحمد
ArchiveAbout
© 2021 Ahmad Atallah