Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How are the process.env.NODE_ENV checks removed from ReactJS production builds?

I know ReactJS converts __DEV__ into "production" !== process.env.NODE_ENV - like this. I saw somewhere that it's converted directly to a boolean, depending on the environment, but that's another confusing point.

I was wondering, though, what specific babel-plugin/process/packages actually removes this condition from the production React (react.min.js), because there are no such conditions in that file.

From my understanding, it's a two-step process:

  1. using a Babel plugin, convert warnings and invariant calls into if ("production" !== process.env.NODE_ENV) calls
  2. remove the entire above conditions (or just its truthy branch?) in the production build, when minifying

How/where is the latter implemented?

like image 339
nevvermind Avatar asked Jan 01 '23 00:01

nevvermind


2 Answers

ReactJS uses Webpack to bundle its production code.
Webpack has a plugin called DefinePlugin, which ReactJS uses. This plugin replaces literal values in the code, values that you can control. Very similar to compiler inlining.

Either I don't get the name of this plugin, or it's just a poor choice. In my research trying to find out how ReactJS cleans up its production code, I've more than once skimmed over the new webpack.DefinePlugin() call. Also, my lack of experience with Webpack didn't help.


As mentioned in the plugin page it's a multi-step process:

1. Original code:

if (!PRODUCTION) {
  console.log('Debug info');
}

if (PRODUCTION) {
  console.log('Production log');
}

2. Inlining done by the Define plugin:

if (!true) {
  console.log('Debug info');
}
if (true) {
  console.log('Production log');
}

3. Minification step, and the final result

console.log('Production log');

The minification/optimization step is done through a tool called Terser, which is what Webpack is using. Terser looks like a fork of UglifyJS, and it, too, has the ability to remove dead code.

So it's:

  1. ReactJS compile production
  2. React configures Webpack with DefinePlugin process.env.NODE_ENV = 'production'
  3. Webpack inlining, done by the Webpack's DefinePlugin
  4. Webpack optimizing
  5. Webpack Terser plugin
  6. Terser finally removes dead code

I'd like to thank @romellem for pointing me in the right direction through this jungle.

PS: Dear future readers, I've written this in the 10th of May 2019. My findings are probably going to be obsolete soon.

like image 51
nevvermind Avatar answered Jan 03 '23 12:01

nevvermind


The code is removed when the JS is uglified (minified).

UglifyJS2 has an option dead_code that "remove[s] unreachable code."

As to how this works, the logic here is fairly complex, but a starting point would be Uglify's eliminate_dead_code function.

like image 31
romellem Avatar answered Jan 03 '23 12:01

romellem