How to set React to production mode when using Gulp
2017 - Edit: anyone trying to set up React in Gulp for a new project: Just use create-react-app
Step I: Add the following to your gulpfile.js somewhere
gulp.task('apply-prod-environment', function() { process.env.NODE_ENV = 'production';});
Step II: Add it to your default task (or whichever task you use to serve/build your app)
// before: // gulp.task('default',['browsersync','watch'], function() {});// after: gulp.task('default',['apply-prod-environment', 'browsersync','watch'], function() {});
OPTIONAL: If you want to be ABSOLUTELY CERTAIN that you are in prod mode, you can create the following slightly enhanced task instead of the one in Step I:
gulp.task('apply-prod-environment', function() { process.stdout.write("Setting NODE_ENV to 'production'" + "\n"); process.env.NODE_ENV = 'production'; if (process.env.NODE_ENV != 'production') { throw new Error("Failed to set NODE_ENV to production!!!!"); } else { process.stdout.write("Successfully set NODE_ENV to production" + "\n"); }});
Which will throw the following error if NODE_ENV is ever not set to 'production'
[13:55:24] Starting 'apply-prod-environment'...[13:55:24] 'apply-prod-environment' errored after 77 μs[13:55:24] Error: Failed to set NODE_ENV to production!!!!
Similar to the other answers, but hopefully gives someone a starting point:
var vendorList = ['react', 'react-dom'];gulp.task('vendor-dev', function() { browserify() .require(vendorList) .bundle() .on('error', handleErrors) .pipe(source('vendor.js')) .pipe(gulp.dest('./build/dev/js'));});gulp.task('vendor-production', function() { process.env.NODE_ENV = 'production'; browserify() .require(vendorList) .bundle() .on('error', handleErrors) .pipe(source('vendor.js')) .pipe(buffer()) .pipe(uglify({ mangle: false })) .pipe(gulp.dest('./build/production/js'));});
The main difference is I am explicitly setting the NODE_ENV prior to bundling the vendor libraries. Gulp tasks aren't guaranteed to run in order.
Am I running in production mode?
If you remove the uglify line (and prior buffer) you will notice that both the dev and production builds are near identical in size - and match in line count.
The difference is the production version will be littered with:
"production" !== "production" ? [show dev error] : [no nothing]
Most reputable minify'ers (I believe) will strip out deadend code, such as the above, which will always result in false.
But really how do I tell?
Easiest method to be sure, would be goto the console of your running application and type:
React.createClass.toString();
The output should be:
"function (e){var t=function(e,t,n){this.__reactAutoBindMap&&c(this),"[....and more and more]
If you find the createClass in the react source, you will see:
createClass: function (spec) { var Constructor = function (props, context, updater) { // This constructor is overridden by mocks. The argument is used // by mocks to assert on what gets mounted. if ("production" !== 'production') { "production" !== 'production' ? warning(this instanceof Constructor, 'Something is calling a React component directly. Use a factory or ' + 'JSX instead. See: react-legacyfactory') : undefined; } // Wire up auto-binding if (this.__reactAutoBindMap) { bindAutoBindMethods(this); }
Notice how the console output skips straight through to this.__reactAutobind
, because you are running in production mode, and using an minify'er, all the !== 'production' warngins and checks have been skipped over.
Unfortunately none of the above answers work, because setting process.env.NODE_ENV
has no effect in Browserify. The resulting bundle still has process.env.NODE_ENV
references in it and hence
- Browserify will not
require()
the React production version modules, - the minifier will not be able to remove dead code, and
- the application will still be running in debug mode.
This is unfortunately not the only place where this approach is offered as the correct answer :-(
The correct approach can be found in e.g.
- https://github.com/hughsk/envify/issues/15#issuecomment-62229101
- https://reactjs.org/docs/optimizing-performance.html#browserify
You need to switch the envify transform to be a global one, e.g.
# note the "-g" instead of the usual "-t"$ browserify ... -g [ envify --NODE_ENV production ] ....
or in gulpfile.js
browserify(...) ... .transform('envify', { global: true, // also apply to node_modules NODE_ENV: debug ? 'development' : 'production', }) ... .bundle() ... .pipe(gulpif(!debug, babelMinify())) // my example uses gulp-babel-minify ...