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
&& 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_ENVwith valuedevelopment
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"
]
},
..........
}
.................
}
}
"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: {.....}
}
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
})
})
],
[...]
}

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:

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.
})
}),
[...]
],
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:
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",.

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:
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"
}
}
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
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.