New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Best way to pass variables through Webpack? #386

Closed
louisscruz opened this Issue Mar 5, 2016 · 16 comments

Comments

Projects
None yet
@louisscruz
Copy link

louisscruz commented Mar 5, 2016

Simple question, but I'm a little lost with the way webpack.DefinePlugin interacts with the application.

For my http calls, I'd like to have a variable that is dynamic based on the process.env.ENV. What's the best way to define a variable in both my webpack.config.js and webpack.prod.config.js files? And what's the best way to make them global variables in the application?

@rbao

This comment has been minimized.

Copy link

rbao commented Mar 5, 2016

Not sure if this is the best way, but here is how I do it in both webpack.config.js and webpack.prod.config.js:

new webpack.DefinePlugin({
  'process.env': {
    'ENV': JSON.stringify(metadata.ENV),
    'NODE_ENV': JSON.stringify(metadata.ENV),
    'HMR': HMR,
    'API_URL': JSON.stringify(process.env.API_URL)
  }
})

Then you can just use it in the code

this._http.get(process.env.API_URL, options);

For development I use dotenv to set the environment variable.
For production just set environment variable as usual.

@louisscruz

This comment has been minimized.

Copy link

louisscruz commented Mar 6, 2016

Perfect. Thanks!

@gdi2290

This comment has been minimized.

Copy link
Owner

gdi2290 commented Mar 7, 2016

@rbao is correct. @rbao can you make a wiki page to talk briefly about this https://github.com/AngularClass/angular2-webpack-starter/wiki

@jshamley

This comment has been minimized.

Copy link

jshamley commented Aug 4, 2016

Don't forget to restart Webpack after adding the environment variables or the system won't recognize them.

@marek1

This comment has been minimized.

Copy link

marek1 commented Sep 21, 2016

I did all those things mentioned above, but

when running npm start i get a process object that contains an EMPTY env object

@m-mital

This comment has been minimized.

Copy link

m-mital commented Oct 28, 2016

I do it like this:

new webpack.DefinePlugin({
     XMPP_HOST: JSON.stringify(process.env.XMPP_HOST || "http://localhost"),
    XMPP_PORT: JSON.stringify(process.env.XMPP_PORT || 5280)
})

and then in JS:

export const XMPP_SERVER_URL = `${XMPP_HOST}:${XMPP_PORT}/http-bind`;
@Remco75

This comment has been minimized.

Copy link

Remco75 commented Nov 20, 2016

@marek1 I noticed the same, there is a strange behaviour: When I de console.log(process) there is an empty env object .

When I do console.log(process.env) it is filled with the proper stuff. I think it has to do with the string 'process.env' we set in the DefinePlugin

@nmccready

This comment has been minimized.

Copy link

nmccready commented Nov 21, 2016

@Remco75

@marek1 I noticed the same, there is a strange behaviour: When I de console.log(process) there is an empty env object .

This strange behavior becomes clear when you look at the packed webpack file. Basically process does not get added to the global scope what so ever. Webpack does a search and replace for anything that is process.env and fills it in with that object specifically everywhere. So essentially it is a new instance of that config object every time. I think this was to not pollute the global space, but for minify purposes seems like a waste.

Is there a option to make it part of the global namespace?

Example:

new webpack.DefinePlugin({
  '__PROCESS__': {
    'ENV': 'production',
  }
})

client code (source mapped):

if(__PROCESS__.ENV === 'production'){
//do something
}

Real Packed Code:

client code (packed):

if(({"ENV":"production"}).ENV === 'production'){
//do something
}

It is not what you assumed it was

window.__PROCESS__ = {"ENV":"production"};
@nmccready

This comment has been minimized.

Copy link

nmccready commented Nov 21, 2016

Also this is talked about in some detail here webpack/webpack#868

To get this working a little nicer for consuming your config objects I wrote this:

function packinize(obj){
  _.each(obj, (v, i) => {
    if(_.isString(v))
      obj[i] = JSON.stringify(v)
    else if(_.isObject(v) && !_.isFunction(v))
      packinize(v)
  })
  return obj
}

const configPlugin = new webpack.DefinePlugin({
  __CONFIG__: packinize(frontendConfig)
})
@jianghai

This comment has been minimized.

Copy link

jianghai commented Nov 29, 2016

So, how could I do if __LANG__ is not defined by DefinePlugin ? Like this

const module = __LANG__ ? require('./' + __LANG__) : require('./zh-cn')

@d3viant0ne d3viant0ne closed this Jan 12, 2017

@HendrikRoth

This comment has been minimized.

Copy link

HendrikRoth commented May 31, 2017

Why not just this?

new webpack.DefinePlugin({
  'process.env': process.env
})
@megamindbrian

This comment has been minimized.

Copy link

megamindbrian commented Jul 10, 2017

Is @jianghai 's method possible? None of these instructions are clear with the use of TypeScript.

@al-the-x

This comment has been minimized.

Copy link

al-the-x commented Dec 9, 2017

@HendrikRoth please don't ever do this, as you've just exposed the environment of the process that you built with to your bundle... And subsequently the internet. Many sensitive values are potentially contained therein, unless DefinePlugin is sanitizing them somehow... Although I can't imagine how.

@gezichenshan

This comment has been minimized.

Copy link

gezichenshan commented Feb 11, 2018

@al-the-x so it means the webpack.DefinePlugin rewrites the process.env as a global variable in a webpack project?

new webpack.DefinePlugin({
  'process.env': require('../config/dev.env')
})

../config/dev.env:

module.exports = {
  NODE_ENV: process.env.NODE_ENV,
  BASE_URL : process.env.BASE_URL,
  MULTILOAN: process.env.MULTILOAN
}

so can we change the process.env in 'process.env': require('../config/dev.env') to another name like 'globalEnv'

@al-the-x

This comment has been minimized.

Copy link

al-the-x commented Mar 2, 2018

In the example from above to which I objected, consider code like this:

// some/project/file.js
if (process.env.NODE_ENV === 'production') {
  doSomethingForProduction();
}

The plugin new webpack.DefinePlugin({ 'process.env.NODE_ENV': process.env.NODE_ENV }) will result in code like this when process.env.NODE_ENV is the string 'production':

// some/project/file.js
if ('production' === 'production') {
  doSomethingForProduction();
}

The config new webpack.DefinePlugin({ 'process.env': process.env }), while simpler, will instruct webpack to replace process.env with an object matching the value provided, so that subsequent keys can be retrieved, e.g.

// some/project/file.js
if (({ /* all of process.env as key: value */ }.NODE_ENV === 'production') {
  doSomethingForProduction();
}

The suggestion you made @gezichenshan, would be much safer, but why not just put those definitions in the DefinePlugin config instead of an external file? If there were lots of values that you needed to pick out of process.env, then maybe a module that did just that would make sense:

const _ = require('lodash');

const KEYS = [
  'NODE_ENV',
  'BASE_URL',
  'SOMETHING_ELSE',
  // . . . so many others
];

module.exports = _.chain(KEYS)
  .map(key => `process.env.${key}`)
  .map(path => [ path, _.get(process.env, path) ])
  .fromPairs()
.value();

But likely that's not practical, either, since that would require a large number of environment variables passed to the startup script. At that point, another external configuration file would be better. Probably one that switches values dependent on... process.env.NODE_ENV...!

@skwid138

This comment has been minimized.

Copy link

skwid138 commented Jul 6, 2018

JSON not JS

I probably should've caught this right away, but I wasn't wrapping the values in JSON.strinify() and was throwing console errors that listed the key, but said it wasn't defined. Which makes sense, but took me a few minutes to figure out why. Hope this helps others in the future.

Originally I was using the below
new webpack.DefinePlugin({ 'process.env': { 'WP_ENV': process.env.WP_ENV, 'WP_DEBUG': process.env.WP_DEBUG, } }),

Then updated it to this to make it work properly
new webpack.DefinePlugin({ 'process.env': { 'WP_ENV': JSON.stringify(process.env.WP_ENV), 'WP_DEBUG': JSON.stringify(process.env.WP_DEBUG), } }),

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment