CommonSenseCode
CommonSenseCode

Reputation: 25369

Read environment variables and then replace them in client-side JS when using gulp for building prod or dev code

So lets say I have some code in js

const myApiKey = 'id_0001'

But instead of harcoding it I want to put it in some bash script with other env vars and read from it and then replace it in the JS

So lets say for prod I would read from prod-env.sh or for dev I would read them from dev-env.sh and then gulp or some other tool does the magic and replaces MY_API_KEY based on whatever is established inside of prod-env.sh or dev-env.sh.

const myApiKey = MY_API_KEY

Update: I want to add I only care about unix OS, not concerned about windows. In golang there is way to read for example envVars.get('MY_API_KEY'), I'm looking for something similar but for JS in the client side.

Upvotes: 4

Views: 6007

Answers (2)

cristian.t
cristian.t

Reputation: 339

If you're using gulp, it sounds like you could use any gulp string replacer, like gulp-replace.

As for writing the gulp task(s). If you are willing to import the environment into your shell first, before running node, you can access the environment via process.env

gulp.task('build', function(){
  gulp.src(['example.js'])
    .pipe(replace('MY_API_KEY', process.env.MY_API_KEY))
    .pipe(gulp.dest('build/'));
});

If you don't want to import the environment files before running node, you can use a library like env2 to read shell environment files.

Another option would be to use js/json to define those environment files, and load them with require.

prod-env.js

{
  "MY_API_KEY": "api_key"
}

gulpfile.js

const myEnv = require('./prod-env')

gulp.task('build', function(){
  gulp.src(['example.js'])
    .pipe(replace('MY_API_KEY', myEnv.MY_API_KEY))
    .pipe(gulp.dest('build/'));
});

Also, for a more generic, loopy version of the replace you can do:

gulp.task('build', function () {
  stream = gulp.src(['example.js']);

  for (const key in process.env) {
    stream.pipe('${' + key + '}', process.env[key]); 
  }

  stream.pipe(gulp.dest('build/'));
});

In that last example I added ${} around the environment variable name to make it less prone to accidents. So the source file becomes:

const myApiKey = ${MY_API_KEY}

Upvotes: 10

Catalyst
Catalyst

Reputation: 3237

This answer is an easy way to do this for someone who doesn't want to touch the code they are managing. For example you are on the ops team but not the dev team and need to do what you are describing.

The environment variable NODE_OPTIONS can control many things about the node.js runtime - see https://nodejs.org/api/cli.html#cli_node_options_options

One such option we can set is --require which allows us to run code before anything else is even loaded.

So using this you can create a overwrite.js file to perform this replacement on any non-node_modules script files:

const fs = require('fs');
const original = fs.readFileSync;

// set some custom env variables
// API_KEY_ENV_VAR - the value to set
// API_KEY_TEMPLATE_TOKEN - the token to replace with the value

if (!process.env.API_KEY_TEMPLATE_TOKEN) {
  console.error('Please set API_KEY_TEMPLATE_TOKEN');
  process.exit(1);
}

if (!process.env.API_KEY_ENV_VAR) {
  console.error('Please set API_KEY_ENV_VAR');
  process.exit(1);
}

fs.readFileSync = (file, ...args) => {
  if (file.includes('node_modules')) {
    return original(file, ...args);
  }
  const fileContents = original(file, ...args).toString(
    /* set encoding here, or let it default to utf-8 */
  );
  return fileContents
    .split(process.env.API_KEY_TEMPLATE_TOKEN)
    .join(process.env.API_KEY_ENV_VAR);
};

Then use it with a command like this:

export API_KEY_ENV_VAR=123;
export API_KEY_TEMPLATE_TOKEN=TOKEN;
NODE_OPTIONS="--require ./overwrite.js" node target.js

Supposing you had a script target.js

console.log('TOKEN');

It would log 123. You can use this pretty much universally with node, so it should work fine with gulp, grunt, or any others.

Upvotes: 1

Related Questions