Doug.Instance

Dynamic Environment Variables with React.js and Parcel

May 29, 2023 | Handleblog environmentreact

DRAFT POST

While working on handleblog, I realized I had a bit of a conundrum related to building the React.js front end: how can I easily modify environment variables without rebuilding the whole React app? Google brought me to this post. However, I quickly realized it would not work great with Parcel for reasons that I will explain below. The overall idea was sound so I created a simple bash script to create a dynamic environment POJO (Plain Old JavaScript Object...POJSO?) that looks something like this:

if [ -f .env ]; then
    source .env
fi
echo "export const env = {" > env.js
echo "    ENV_VAR_1: '$ENV_VAR_1'," >> env.js
echo "    ENV_VAR_2: '$ENV_VAR_2'," >> env.js
echo "};" >> env.js

Executing this script creates a file named env.js with the actual values of each environment variable either from your local environment or .env as follows:

export const env = {
    ENV_VAR_1: 'Value of ENV_VAR_1',
    ENV_VAR_2: 'Value of ENV_VAR_2',
};

Then all that is needed is to import this object and reference it instead of process.env as follows:

import { env } from '../env';

const myVar = env.ENV_VAR_1;

Now that we have working code, how do we make it so we can dynamically change this magical env.js file? Parcel is super fast and easy to configure - in fact it boasts being a "zero configuration build tool". However, when you want to do something unsupported, you need...configuration. More specifically, you need a plugin to allow you to ignore the env.js file so it isn't included during the build and packaging of your app. Thanks to this thread and I was able to find this plugin. Following the instructions looks something like this:

.parcelrc

{
  "extends": "@parcel/config-default",
  "resolvers": ["parcel-resolver-ignore", "..."]
}

package.json

  "parcelIgonore": [
    "env.js"
  ],

index.html

      <script type="module" src="env.js"></script>

Ever the minimalist, I ignored the part about copying the file to the output folder until I realized this was required for running the parcel server in dev mode. So I added parcel-reporter-static-files-copy as follows.

package.json

    "parcel-reporter-static-files-copy": "^1.5.0",