33

I need to run React in production mode, which presumably entails defining the following somewhere in the enviornment:

process.env.NODE_ENV = 'production';

The issue is that I'm running this behind Tornado (a python web-server), not Node.js. I also use Supervisord to manage the tornado instances, so it's not abundantly clear how to set this in the running environment.

I do however use Gulp to build my jsx files to javascript.

Is it possible to somehow set this inside Gulp? And if so, how do I check that React is running in production mode?

Here is my Gulpfile.js:

'use strict';

var gulp = require('gulp'),
        babelify = require('babelify'),
        browserify = require('browserify'),
        browserSync = require('browser-sync'),
        source = require('vinyl-source-stream'),
        uglify = require('gulp-uglify'),
        buffer = require('vinyl-buffer');

var vendors = [
    'react',
    'react-bootstrap',
    'jquery',
];

gulp.task('vendors', function () {
        var stream = browserify({
                        debug: false,
                        require: vendors
                });

        stream.bundle()
                    .pipe(source('vendors.min.js'))
                    .pipe(buffer())
                    .pipe(uglify())
                    .pipe(gulp.dest('build/js'));

        return stream;
});

gulp.task('app', function () {
        var stream = browserify({
                        entries: ['./app/app.jsx'],
                        transform: [babelify],
                        debug: false,
                        extensions: ['.jsx'],
                        fullPaths: false
                });

        vendors.forEach(function(vendor) {
                stream.external(vendor);
        });

        return stream.bundle()
                                 .pipe(source('build.min.js'))
                                 .pipe(buffer())
                                 .pipe(uglify())
                                 .pipe(gulp.dest('build/js'));

});

gulp.task('watch', [], function () {
    // gulp.watch(['./app/**/*.jsx'], ['app', browserSync.reload]);
    gulp.watch(['./app/**/*.jsx'], ['app']);
});

gulp.task('browsersync',['vendors','app'], function () {
        browserSync({
            server: {
                baseDir: './',
            },
            notify: false,
            browser: ["google chrome"]
    });
});

gulp.task('default',['browsersync','watch'], function() {});
vgoklani
  • 10,685
  • 16
  • 63
  • 101
  • From what I can gather from the react documentation on production vs developments means using a different artifact. See the download page: http://facebook.github.io/react/downloads.html – Ciaran Liedeman Sep 12 '15 at 10:45
  • React is installed via npm, i.e. "npm install react". There is a seamless way of switching between dev and production, that's what I'm asking for in the question – vgoklani Sep 12 '15 at 18:35
  • 1
    You can set the environment variable before running gulp in production : NODE_ENV='production' gulp. The react library will read from this to remove logging messages and alerts and uglifyJS will take care of the rest [http://facebook.github.io/react/downloads.html](http://facebook.github.io/react/downloads.html). – Rakan Nimer Sep 13 '15 at 12:31

5 Answers5

28

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!!!!
Community
  • 1
  • 1
Monarch Wadia
  • 4,400
  • 4
  • 36
  • 37
  • In what case would the error be thrown? Is there a situation where you can't write to your personal environment variables? – Kris Selbekk Feb 24 '16 at 07:09
  • 3
    no such case to my knowledge. optional step is probably unnecessary actually. – Monarch Wadia Feb 24 '16 at 22:20
  • Correct me if I am wrong, but the order of tasks in gulp isn't technically guaranteed. So could watch and browsersync not happen before applying the prod environment? – Chris Mar 22 '16 at 09:18
  • I was expecting a sensible change in size, but it seems that the difference is about 2ko difference (not compressed), could someone confirm? – Vadorequest Mar 29 '16 at 10:15
  • http://stackoverflow.com/questions/40881633/how-to-fix-redux-node-env-errors-with-gulp-browserify @monarch – GN. Nov 30 '16 at 06:24
8

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.

Chris
  • 54,599
  • 30
  • 149
  • 186
2

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.

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
    ...
Stefan Becker
  • 5,695
  • 9
  • 20
  • 30
1

To set React in production mode you need to set your NODE_ENV variable to production and uglify your JS as an extra step.

You're already taking care of the uglification, for setting your NODE_ENV variable :

  • Set the variable while running the gulp task :

NODE_ENV='production' gulp

  • OR set it from inside your gulpfile by doing something like this :

gulp.task('set-production-env', function() { return process.env.NODE_ENV = 'production'; });

Rakan Nimer
  • 574
  • 5
  • 9
  • how do I check that React is working in production mode? Is there a way to check the mode in the dev console? – vgoklani Sep 14 '15 at 12:41
  • 2
    One way would be to trigger something that would cause a warning and check that no warning logs are present in the console. For example, map an array to a bunch of components and don't give them a key. If nothing is written to the console, then you're in production mode. Also, make sure the react lib is properly minified, uglified and gzipped for filesize. – Rakan Nimer Sep 15 '15 at 07:34
  • Thanks for your help :) – vgoklani Sep 29 '15 at 19:29
  • another way is to check the size of your final, minified app/browserify bundle. i just saw my bundle size drop by about 100kB with production set. – akarve Mar 18 '16 at 03:11
0

Also you may use handy way with gulp-environments:

var environments = require('gulp-environments');

var production = environments.production;

gulp.src(paths.js)
    .pipe(concat("app.js"))
    // only minify the compiled JS in production mode
    .pipe(production(uglify()))
    .pipe(gulp.dest("./public/app/js/"));

To run gulp in production mode:

gulp build --env=production
Nick
  • 9,735
  • 7
  • 59
  • 89