webpack-cli: NODE_ENV not set on process.env

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

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 29
  • Comments: 35 (8 by maintainers)

Commits related to this issue

Most upvoted comments

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.

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.

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?

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

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

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") })
]

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
}

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

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

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") }),

&& 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.

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.

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 😕

@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

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

my idea.

running webpack or NODE_ENV=development webpack

not set --mode option.

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,

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” ] }, … } … } }

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,it works

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?

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

  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.