Skip to content
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
Closed

Best way to pass variables through Webpack? #386

louisscruz opened this issue Mar 5, 2016 · 16 comments

Comments

@louisscruz
Copy link

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
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
Copy link
Author

Perfect. Thanks!

@PatrickJS
Copy link
Owner

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

@jshamley
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
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

@herr-bubu
Copy link

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
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
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
Copy link

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
Copy link

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

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

@HendrikRoth
Copy link

Why not just this?

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

@ghost
Copy link

ghost commented Jul 10, 2017

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

@al-the-x
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
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
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
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
Labels
None yet
Projects
None yet
Development

No branches or pull requests