Webpack-cli: NODE_ENV not set on process.env

Created on 18 Apr 2018  路  35Comments  路  Source: webpack/webpack-cli

Do you want to request a feature or report a bug?

Bug

What is the current behavior?

Currently, mode only sets the value for NODE_ENV in the DefinePlugin but not changes the process.env.NODE_ENV.

For example, Babel depends on this env variable and when used with webpack --mode=production it will still run in development mode.

If the current behavior is a bug, please provide the steps to reproduce.

Running webpack --silent --mode=production && echo $NODE_ENV

This will NOT print anything.

Run NODE_ENV=production && webpack --silent --mode=production && echo $NODE_ENV

This will print production

What is the expected behavior?

Running webpack --silent --mode=production && echo $NODE_ENV should print production

Most helpful comment

I think this bit of information should be reflected in the documentation: https://webpack.js.org/concepts/mode/. As it reads now - "Provides process.env.NODE_ENV with value XXXXXX", this lead me to believe that passing the mode as a CLI argument set process.env.NODE_ENV for the whole environment.

All 35 comments

&& echo $NODE_ENV will show NODE_ENV value after previous command finished successfully, webpack will change it only while it runs, it doesn't change it for the entire system.

What is the way to log it during webpack process? It doesn鈥檛 seem to be set since Babel isn鈥檛 picking the right configuration which is based on that.

@okonet if the build takes sufficiently long you might want to try https://unix.stackexchange.com/questions/29128/how-to-read-environment-variables-of-a-process on linux

I don't know exactly at what point exactly webpack sets process.env.NODE_ENV, also don't know if loaders should rely on it, by reading https://github.com/webpack/webpack/issues/2537#issuecomment-221024348 one could conclude that it doesn't affect loaders source environment.

So you still have to set it at command level, so I would affect entire execution context.

AFAIK regardless of mode webpack does not set process.env.NODE_ENV.

If you want it set it has to be explicitly done by the user in the webpack config.

If this is not correct please show the line of code in the webpack 4 sources where this environment variable is set.

also don't know if loaders should rely on it

babel-loader doesn't rely on it per-se but since the loader executes babel-core which relies on it, it might break things right now.

If you want it set it has to be explicitly done by the user in the webpack config.

Then the documentation is misleading and needs to be updated? It should probably explicitly say that it only does new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("development") }),

But honestly I think that there is a problem with the mental model here. If something called in relation to node process.env then the mode should set it to that value during compile time.

I think this bit of information should be reflected in the documentation: https://webpack.js.org/concepts/mode/. As it reads now - "Provides process.env.NODE_ENV with value XXXXXX", this lead me to believe that passing the mode as a CLI argument set process.env.NODE_ENV for the whole environment.

I鈥檇 argue it should actually set the variable to allow related tools be executed in the right context.

I was very surprised that --mode=production doesn't set process.env.NODE_ENV with value production within webpack.config.js but only _provides_ this variable for your bundles.

So basically just a replacement for the old fashioned:

plugins: [
  new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("production") })
]

The manual literally says:

Provides process.env.NODE_ENV with value development

And the docs for sass-loader includes an example using:

process.env.NODE_ENV !== 'production' ? 'style-loader' : MiniCssExtractPlugin.loader

I guess this will silently use style-loader since process.env.NODE_ENV is always undefined?

I was hoping to do something similar, so what's the alternative?

How can I check which --mode is being run, so I can make variations in my webpack.config.js between development and production modes?

To others looking for a solution, I found it here: export a function instead of an object, and it will be called with parsed/normalized environment and argument objects.

(I'm submitting a PR for the sass-loader example, which doesn't work.)

Honestly, thanks a million @mindplay-dk, this was driving me nuts... I never realised there was an argv being passed in. Just to have it here:

module.exports = (env, argv) => {
     let production = argv.mode === 'production'

     ...
     return correctConfig
}

In package.json
"scripts": {
"dev": "webpack --mode development --watch",
"build": "webpack --mode production",

}

In webpack.config.js
module.exports = (env, options) => {
const devMode = options.mode !== 'production';
return {
entry: ...
output: .....
module: {
....
{
test: /.(sa|sc|c)ss$/,
use: [
devMode ? "style-loader" : MiniCssExtractPlugin.loader,
"css-loader",
"sass-loader"
]
},
..........
}
.................
}
}

  1. package.json
    replace ./conf/webpack.config.js with your webpack config file path.

"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "webpack --config ./conf/webpack.config.js --mode development",
"build": "webpack --config ./conf/webpack.config.js --mode production "
},

2 . webpack.config.js

add plugin parameter value into webpack config.
module.exports = {
entry: ...........,
plugins: [
new webpack.DefinePlugin({
'process.env': {
'NODE_ENV': '"' + process.env.NODE_ENV + '"'
}
}),
],
output: {.....}
}

  1. command to generate build

NODE_ENV=dev npm run dev or
NODE_ENV=prod npm run build

It will set the environment as you pass on command line.

I get the same result
But I found that
console.log(process.env); // {}
console.log(process.env.NODE_ENV); // development

Honestly, thanks a million @mindplay-dk, this was driving me nuts... I never realised there was an argv being passed in. Just to have it here:

module.exports = (env, argv) => {
     let production = argv.mode === 'production'

     ...
     return correctConfig
}

Thanks锛宨t works

my idea.

running webpack or NODE_ENV=development webpack

not set --mode option.

```javascript:webpack.config.js
const node_env = process.env.NODE_ENV ? process.env.NODE_ENV : 'production';
const devMode = node_env !== 'production';
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = {
mode: node_env,
output: {
...
},
plugins: [
new MiniCssExtractPlugin({
// Options similar to the same options in webpackOptions.output
// both options are optional
filename: devMode ? '[name].[hash].css' : '[name].css',
chunkFilename: devMode ? '[id].[hash].css' : '[id].css',
})
],
module: {
...
}
};
```

Best regards,

This does not seem to be working with the -p flag as expected.

Here's the docs when you run webpack --help:

-p           shortcut for --optimize-minimize --define
               process.env.NODE_ENV="production"                       [boolean]

This seems to clearly state that process.env.NODE_ENV should have the string value of "production" when run with the -p flag, even if that environment variable is not otherwise defined externally. But that doesn't seem to be the case. Added a little bit of debugging code to my webpack.config.js file:

const isProduction = process.env.NODE_ENV === "production";

console.log("isProduction: " + isProduction);
console.log("NODE_ENV: " + process.env.NODE_ENV);

And I get the following output with webpack -p or without the -p flag:

isProduction: false
NODE_ENV: undefined

Note that I currently cannot use the export-function approach (which is cool by the way!) because it doesn't work with another library that is expecting the export to be an object. But regardless, based on the webpack --help information, this definitely appears to be a bug.

@paulirwin,

That will define process.env.NODE_ENV within the context of your bundled code. You need to run webpack with NODE_ENV=production (or set that globally).

Totally agree with you @okonet
This is very strange bug. The funny part is that when you pass this config

{
[...]
  plugins: [
      new DefinePlugin({
        "process.env": JSON.stringify({
          ...dotenv.config({
            path: `${ROOT_DIR}/environments/.${env}.env`
          }).parsed,
          NODE_ENV: env
        })
      })
    ],
[...]
}

code_example
The app can read environments variables even with NODE_ENV as passed value from webpack BUT when you try to access it through process.env.NODE_VALUE it will give you different variable LOL.

Check the result out:
result

I'm using those following versions for my app.

{
    "webpack": "^4.35.0",
    "webpack-cli": "^3.3.4",
    "webpack-node-externals": "^1.7.2"
}

Still buggy
module.exports.devtool = '#source-map'; module.exports.plugins = (module.exports.plugins || []).concat([ new webpack.DefinePlugin({ 'process.env': { NODE_ENV: '"development"', }, 'process.env.API_URL': JSON.stringify(${env.API_URL}), }), new webpack.optimize.UglifyJsPlugin({ sourceMap: true, compress: { warnings: false, }, }), new webpack.LoaderOptionsPlugin({ minimize: true, }), ]);

Hello @BonBonSlick , I guess better to leave NODE_ENV key for webpack and use alternative names. I know this is annoying but give you a solution for the mean time till they find a solution.

@AhmedBHameed I hardcoded for a while envs, will take a look later.

You can inject multi environment using the following code.

// Webpack config as a function

const environments = dotenv.parse(
    fs.readFileSync(`${ROOT_DIR}/environments/.${env}.env`)
  );
environments["ENV_NAME"] = env;
plugins: [
      new DefinePlugin({
        "process.env": JSON.stringify({
          PRIVATE_ENV: environments // or use it as variable for environment file path.
        })
      }),
      [...]
    ],

https://stackoverflow.com/questions/55259238/what-is-the-difference-between-webpack-env-production-and-mode-production

Basically --mode just sets "process.env.NODE_ENV" on DefinePlugin only. And you can access it inside function exported from your webpack.config.js.

--env also has nothing to do with process.env and it operates on object passed to your exported function.

One trick would be to assign process.env.NODE_ENV manually like this:

var config = {
  entry: './app.js'
  //...
};

module.exports = (env, argv) => {
  process.env.NODE_ENV = argv.mode;

  return config;
};

process.env.NODE_ENV will be correctly defined in other configs you use like postcss.config.js

or just use cross-env and if you want --mode functionality as well do this(for webpack to add it to DefinePlugin as well):

var config = {
  entry: './app.js'
  mode: process.env.NODE_ENV,
  // ...
};

Note it won't be available in argv.mode then if you don't pass it with cmd line

first try

new webpack.DefinePlugin({
  "process.env.env": JSON.stringify("development"),
})

console.log("process.env", JSON.stringify(process.env, null, 2))
console.log("process.env.NODE_ENV", process.env.NODE_ENV)

// logs

process.env {}
process.env.NODE_ENV development

second try

new webpack.DefinePlugin({
  "process.env": JSON.stringify({ NODE_ENV: 'development' }),
})

console.log("process.env", JSON.stringify(process.env, null, 2))
console.log("process.env.NODE_ENV", process.env.NODE_ENV)

// logs

process.env { NODE_ENV: "development" }
process.env.NODE_ENV development

For example, Babel depends on this env variable [process.env.NODE_ENV] and when used with webpack --mode=production it will still run in development mode.

I agree that this is very confusing. As an example, React looks to process.env.NODE_ENV and successfully creates a production build if Webpack's mode is set to "production", because DefinePlugin does a search-and-replace.

But build tools don't have access to this variable. So you'd need to set process.env.NODE_ENV as well.

We end up with all these concepts:

  • mode=production
  • "Webpack environment"
  • NODE_ENV on DefinePlugin
  • the "real" process.env.NODE_ENV during build
  • optimization.nodeEnv
  • NODE_ENV on EnvironmentPlugin

I haven't seen anyone suggesting setting the variable for the script execution on the command line just like this:

NODE_ENV=production webpack --mode=production

Am I missing a reason this isn't a good solution?

@adamwathan I suggested it in my comment (which I incidentally wrote after I got the purge option to work with Tailwind!)

Nothing wrong with that. But using https://github.com/kentcdodds/cross-env instead seems to be a very popular (and safer) alternative, and is used by all kinds of projects.

Alternatively, I do it like this:

// webpack.config.js
module.exports = (env) => {
  process.env.NODE_ENV = env.environment;

  return {
    mode: env.environment,
    // ...
  }
}
// webpack --env.environment=production

IMHO if "mode" is specified, no matter wether via command line or the configuration file, process.env.NODE_ENV should be set to that value, the behaviour should be as simple as that. I've spent days trying to understand why it wasn't being set, and the behaviour of the "-p" flag is totally misleading :/

I am facing the issue, "You are currently using minified code outside of NODE_ENV === 'production'.....". While tried to put console inside the bundle file, NODE_ENV is coming as undefind. Can u please give a solution for this.
for generate Bundle in locally "set NODE_ENV=production && node --max-old-space-size=5120 ./node_modules/webpack/bin/webpack.js --env production",.
image

This is an absolutely perfect example of why my love meter for "modern javascript" constantly veers back into the negative

I think we should look how other tools do it, maybe we just need improve our docs

For future seekers, now we support --node-env, what is benefits:

  • You can avoid using the cross-env package:

Before:

{
  "scripts": {
    "build": "cross-env NODE_ENV=production webpack --config build/webpack.config.js"
  }
}

Now (you can remove the cross-env if you don't use it somewhere else):

{
  "scripts": {
    "build": "webpack --node-env=production --config build/webpack.config.js"
  }
}
  • the mode option respect the --node-env option if you don't set the mode option explicit using CLI options or in configuration(s), i.e. --node-env production set process.env.NODE_ENV and mode to production
Was this page helpful?
0 / 5 - 0 ratings

Related issues

billyjanitsch picture billyjanitsch  路  3Comments

luillyfe picture luillyfe  路  4Comments

evenstensberg picture evenstensberg  路  5Comments

aleksandrlat picture aleksandrlat  路  3Comments

sam-s4s picture sam-s4s  路  5Comments