Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to set process.env before a browserified script is run?

The initial html comes from the back-end. The server has a defined process.env.NODE_ENV (as well as other environment variables). The browserified code is built once and runs on multiple environments (staging, production, etc.), so it isn't possible to inline the environment variables into the browserified script (via envify for example). I'd like to be able to write out the environment variables in the rendered html and for browserified code to use those variables. Is that possible?

Here's how I imagine that being done:

<html>
  <head>
    <script>window.process = {env: {NODE_ENV: 'production'}};</script>
    <script src="/build/browserified_app.js"></script>
  </head>
</html>
like image 860
Yuriy Nemtsov Avatar asked Oct 24 '14 02:10

Yuriy Nemtsov


People also ask

Can I set process env?

You can set the environment variable through process global variable as follows: process. env['NODE_ENV'] = 'production'; Works in all platforms.

What is process env NODE_ENV?

NODE_ENV is an environment variable that stands for node environment in express server. The NODE_ENV environment variable specifies the environment in which an application is running (usually, development or production).

Can environment variables contain newlines?

When you run a Docker container, you can pass environment variables to the run command. However, the --env-file option has a limitation in that it doesn't handle newline characters.


5 Answers

Instead of hardcoding enviroment variables here and there, use the envify plugin.

npm install envify 

This plugin automatically modifies the process.env.VARIABLE_HERE with what you passed as an argument to envify.

For example:

browserify index.js -t [ envify --DEBUG app:* --NODE_ENV production --FOO bar ] > bundle.js

In your application process.env.DEBUG will be replaced by app:*, process.env.NODE_ENV will be replaced by production and so on. This is a clean && elegant way in my opinion to deal with this.

like image 141
alessioalex Avatar answered Oct 15 '22 00:10

alessioalex


You can change your entry point file, which would basically to do such setup and then require the original main file.

process.env.NODE_ENV = 'production';
require('app.js');

Other way (imo much cleaner) is to use transform like envify which replaces your NODE_ENV in the code with the string value directly.

Option 1

I think your approach should generally work, but I would't write directly to process.env since I am pretty much sure that it gets overwritten in the bundle. Instead you can make global variable like __env and then in the actual bundle code set it to process.env in your entry file. This is untested solution, but I believe it should work.

Option 2

Use localStorage and let your main script read variables from there upon initialization. You can set variables to localStorage manually or you can even let the server provide them if you have them in there. Developer would just open console and type something like loadEnv('production'), it would do XHR and store the result in the localStorage. Even with manual approach there is still an advantage that these doesn't need to hard-coded in html.

If manual doesn't sound good enough and server is a dead end too, you could just include all variables from all environments (if you have them somewhere) in the bundle and then use switch statement to choose correct ones based on some conditions (eg. localhost, production host).


Thinking about this, you are definitely out of scope of Browserify with your needs. It can make bundle for you, but if you don't want these information in the bundle, you are on your own.

like image 22
FredyC Avatar answered Oct 15 '22 00:10

FredyC


So I've decided it's the web server's job to insert the environment variables. My scenario required different loggers per environment (e.g. 'local','test','prod').

code:

var express = require('express')
  , replace = require('replace');

...

var app = express();
var fileToReplace = <your browserified js here>;
replace({
  regex: 'ENV_ENVIRONMENT'
  , replacement: process.env.ENVIRONMENT
  , paths: [fileToReplace]
});

...

app.listen(process.env.PORT);

I hardcoded 'ENV_ENVIRONMENT', but you could create an object in your package.json and make it configurable.

This certainly works, and it makes sense because it's possibly the only server entry point you have.

like image 31
aaaaaa Avatar answered Oct 15 '22 02:10

aaaaaa


I had success writing to a json file first, then importing that json file into anywhere that needed to read the environment.

So in my gulp file:

import settings from './settings';
import fs from 'fs';
...
fs.writeFileSync('./settings.json', JSON.stringify(settings));

In the settings.js file:

if(process.env.NODE_ENV) {
    console.log('Starting ' + process.env.NODE_ENV + ' environment...');
} else {
    console.log('No environment variable set.');
    process.exit();
}

export default (() => {
    let settings;

    switch(process.env.NODE_ENV) {
        case 'development':
            settings = {
                baseUrl: '...'
            };
            break;
        case 'production':
            settings = {
                baseUrl: 'some other url...'
            };
            break;
    }

    return settings;
})();

Then you can import the settings.json file in any other file and it will be static, but contain your current environment:

import settings from './settings.json';
...
console.log(settings.baseUrl);

I came here looking for a cleaner solution...good luck!

like image 35
David Sinclair Avatar answered Oct 15 '22 00:10

David Sinclair


I run into this problemn building isomorphic react apps. I use the following (ok, it's a little hacky) solution:

I assign the env to the window object, ofcourse I don't expose all env vars, only the ones that may be public (no secret keys of passwords and such).

// code...
const expose = ["ROOT_PATH", "ENDPOINT"];
const exposeEnv = expose.reduce(
    (exposeEnv, key) => Object.assign(exposeEnv, { [key]: env[key] }), {}
);
// code...
res.send(`<DOCTYPE html>
// html...
<script>window.env = ${JSON.stringify(exposeEnv)}</script>
// html...
`);
// code...

then, in my applications clients entry point (oh yeah you have to have a single entry point) I do this:

process.env = window.env;

YMMV AKA WFM!

like image 45
Elmer Avatar answered Oct 15 '22 02:10

Elmer