Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

node programmatically set process environment variables not available to imported modules

I'm new, hopefully this question is properly formatted and formulated. Can't wait to see your answers on this question. Let's get to it..

Context

Past weekend I was trying to implement es2015 syntax support in my create-react-app configuration files, which was straight forward. All I had to do was use babel-register and babel-preset-env to get it working. So far so good you could say, however it wasn't all good. After some hours of searching I found that process.env variables are not passed through to imported modules. The code below will demonstrate my issue.

The code

package.json

{
  ...
  "scripts": [
    "good": "NODE_ENV=development BABEL_ENV=development node -r babel-register scripts/start.js",
    "bad": "node -r babel-register scripts/start.js"
  ],
  "devDependencies": {
    "babel-core": "^6.26.3",
    "babel-preset-env": "^1.7.0",
    "babel-register": "^6.26.0"
  }
  ...
}

.babelrc

{
  "presets": [ "env" ]
}

scripts/start.js

'use strict'

process.env.NODE_ENV = 'development';
process.env.BABEL_ENV = 'development';

// Always works
const a = require('../src/a');
// Only when environment variables are passed in via the CLI
import b from '../src/b';

console.log('Bye bye..');  

src/a.js

'use strict'

console.log('Module A:', process.env.NODE_ENV);

const a = { name: "Module A" };
export default a;

src/b.js

'use strict'

console.log('Module B:', process.env.NODE_ENV);

const b = { name: "Module B" };
export default b;

Running the code

Below you will see the output of both npm scripts:

npm run good
# Outputs:
Module B: development
Module A: development
Bye bye..

npm run bad
# Outputs:
Module B: undefined
Module A: development
Bye bye..

My question(s)

  1. Why aren't programmatically set environment variables passed through to imported modules?
  2. Can this be fixed while keeping es2015 syntax? (e.g. using a babel plugin?)

More info

Just moving my process.env.NODE_PATH over to the CLI won't work, create-react-app programmatically sets environment variables at multiple places in their configuration/script files. I have listed a few links below, pointing to the create-react-app repo and some of the files that are giving me troubles.

  • create-react-app A link to the create-react-app repo.
  • scripts/start.js This script sets both process.env.NODE_ENV and process.env.BABEL_ENV.
  • config/env.js This config file sets process.env.NODE_PATH.

Note(s)

From my current understanding, create-react-app has little to none to do with the problem I'm having. I'm interested in why programmatically set environment variables are not passed through to imported modules.

My setup

  • OS: Ubuntu 16.04
  • Node: v8.11.2
  • Npm: 6.3
like image 473
sxkx Avatar asked Aug 07 '18 14:08

sxkx


2 Answers

ES6 imports are hoisted. This means they will run before the rest of the code regardless of where they are in the source. The result is that b.js will run before you have set process.env.NODE_ENV = 'development'.

Babel's output will be consistent with this and will simulate hoisted imports by moving b's require statement to the top of the file. Babel will create a start file that looks like:

'use strict';

var _b = require('../src/b');

var _b2 = _interopRequireDefault(_b);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

process.env.NODE_ENV = 'development';
process.env.BABEL_ENV = 'development';

// Always works
var a = require('../src/a');
// Only when environment variables are passed in via the CLI

It should be clear looking at that why this isn't working.

[ As a side note, many people strongly recommend that you don't set NODE_ENV at runtime ]

like image 170
Mark Avatar answered Sep 24 '22 14:09

Mark


Answer to my second question

Thanks to the insights provided by @Mark Meyer I was able to get it to work.

scripts/start.js

'use strict'  

import '../config/devEnv';

config/devEnv.js

'use strict'  

process.env.NODE_ENV = 'development';
process.env.BABEL_ENV = 'development';

Now the environment variable setters are hoisted as well, making them available to all imported modules.

like image 29
sxkx Avatar answered Sep 23 '22 14:09

sxkx