DefinePlugin fails to inject process.env.NODE_ENV into React without UglifyJSPlugin

package.json:

{
  "name": "test",
  "version": "0.0.1",
  "dependencies": {},
  "devDependencies": {
    "react": "0.12.2",
    "webpack": "1.7.2"
  }
}

main.js:

var React = require('react')
console.log(process.env.NODE_ENV)

webpack.config.js:

var webpack = require('webpack')

module.exports =  {
  entry: {
    app: './main'
  },
  output: {
    path: '_dist',
    filename: 'out.js'
  },
  resolve: {
    extensions: ['', '.js', '.json']
  },
  plugins: [
    new webpack.DefinePlugin({
      'process.env': {
        'NODE_ENV': '"production"'
      }
    })
  ]
}

Place all these files into the same directory and then run:

npm install
rm -rf _dist && ./node_modules/.bin/webpack

Then inspect _dist/out.js. You will see that process.env.NODE_ENV has been successfully injeted to main.js module (line 47):

var React = __webpack_require__(1)
console.log(("production"))

But all entries of process.env.NODE_ENV inside React modules remain intact, e.g. line 314:

("production" !== process.env.NODE_ENV ? warning(
  standardName == null,
  'Unknown DOM property ' + name + '. Did you mean ' + standardName + '?'
) : null);

You can verify this by searching for ("production") and process.env.NODE_ENV. Changing definition to a flat one doesn’t help:

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

However, when I add UglifyJSPlugin, injection starts working as intended: UglifyJS prints a lot of Condition always false messages, and there are no occurrences of NODE_ENV inside the minified out.js.

Author: Fantashit

5 thoughts on “DefinePlugin fails to inject process.env.NODE_ENV into React without UglifyJSPlugin

  1. when you take a closer look to the react file you’ll notice that it looks like this:

    ...
    if ("production" !== process.env.NODE_ENV) {
    ...
        ("production" !== process.env.NODE_ENV ? warning(
          standardName == null,
          'Unknown DOM property ' + name + '. Did you mean ' + standardName + '?'
        ) : null);
    ...
    }
    ...

    webpack already replaces the top-most if ("production" !== process.env.NODE_ENV) with if (false) and skips the block. So the process.env.NODE_ENV in the block never gets executed (UglifyJs will remove it, dead code).

    ...
    if (false) {
    ...
        ("production" !== process.env.NODE_ENV ? warning(
          standardName == null,
          'Unknown DOM property ' + name + '. Did you mean ' + standardName + '?'
        ) : null);
    ...
    }
    ...
  2. The DefinePlugin just replaces occurrences of the given identifiers with the given expressions. After that, UglifyJS detects dead code blocks and removes them.

  3. @skozin Webpack does all of its AST walking and transforming together on an AST, and it does so while performing static analysis, so if it recognizes that it can’t get into one side of an if, it won’t run any transforms in that part. DefinePlugin hooks into that transform/traversal so it won’t bother substituting stuff into the if(false){ side of the if.

Comments are closed.