loading...
Cover image for Injecting Environment Variables into a React App

Injecting Environment Variables into a React App

eidellev profile image Lev Eidelman ・2 min read

When creating a react app using create-react-app, we may sometimes want to inject some environment variables at build time.
For instance, our team wanted to console.log the build time, app version and some git information when the app starts.

This is the solution we came up with.

The Build script

We added a node script to scripts/build.js. The script uses shelljs to append information to the environment and run react-scripts and simple-git to execute git commands.

const path = require('path');
const shell = require('shelljs');
const simpleGit = require('simple-git');
const { version } = require('../package.json');

const args = process.argv.slice(2);
const isDev = args.includes('--dev');

if (!shell.which('git')) {
  shell.echo('Cannot build without git');
  shell.exit(1);
}

if (!shell.which('yarn')) {
  shell.echo('Cannot build without yarn');
  shell.exit(1);
}

const workingDir = path.resolve(__dirname, '../');
const git = simpleGit(workingDir);

function getCurrentBranch() {
  return new Promise((fulfill, reject) => {
    git.status((err, status) => {
      if (err) {
        reject(err);
        return;
      }

      fulfill(status.current);
    });
  });
}

function getCurrentCommit() {
  return new Promise((fulfill, reject) => {
    git.revparse(['HEAD'], (err, hash = '') => {
      if (err) {
        reject(err);
        return;
      }
      fulfill(hash.slice(0, 7));
    });
  });
}

(async () => {
  try {
    const branch = await getCurrentBranch();
    const commit = await getCurrentCommit();
    const buildTime = new Date().toUTCString();

    shell.env.REACT_APP_VERSION = version;
    shell.env.REACT_APP_GIT_BRANCH = branch;
    shell.env.REACT_APP_GIT_COMMIT = commit;
    shell.env.REACT_APP_BUILD_TIME = buildTime;

    if (isDev) {
      shell.exec('yarn react-scripts start');
      return;
    }

    shell.exec('yarn react-scripts build');
  } catch (err) {
    shell.echo('Failed to gather build info', err);
    shell.exit(1);
  }
})();

We substitute react-script in package.json for our build script:

...
  "scripts": {
    "start": "node ./scripts/build --dev",
    "build": "node ./scripts/build",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
    "lint": "eslint .",
    "lint:fix": "eslint . --fix"
  }
...


In the app

We added src/utils/printBuilInfo.js. It prints out our environment variables in a style inspired by Vue devtools.

function print(title, info) {
  // eslint-disable-next-line
  console.log(
    `%c ${title} %c ${info} %c`,
    'background: #f26d21; padding: 1px; border-radius: 3px 0 0 3px;  color: #fff',
    'background: #009eed; padding: 1px; border-radius: 0 3px 3px 0;  color: #fff',
    'background:transparent',
  );
}

export default function printBuildInfo() {
  print('Version', process.env.REACT_APP_VERSION);
  print('Branch', process.env.REACT_APP_GIT_BRANCH);
  print('Commit', process.env.REACT_APP_GIT_COMMIT);
  print('Build Time', process.env.REACT_APP_BUILD_TIME);
}


We use it in src/index.js:

import React from 'react';
import ReactDOM from 'react-dom';
import * as serviceWorker from './serviceWorker';
import App from './App';
import printBuildInfo from './utils/printBuildInfo';
import './styles/index.scss';

printBuildInfo();

ReactDOM.render(<App />, document.getElementById('root'));

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();

Posted on by:

Discussion

markdown guide
 

Hey Lev, thank you for your contribution. An improvement that you could do in your post is provide some comments in your script. It helps for beginners read easily your logic.

Thank you again this article helped me to solve an issue that I have.