web-dev-qa-db-fra.com

Comment définir React en mode de production lors de l'utilisation de Gulp

Je dois exécuter React en mode production, ce qui implique probablement de définir les éléments suivants quelque part dans l’environnement:

process.env.NODE_ENV = 'production';

Le problème est que je l’utilise derrière Tornado (un serveur Web python), pas Node.js. J'utilise également Supervisord pour gérer les instances de tornade. Il n'est donc pas très clair comment définir cela dans l'environnement d'exécution.

J'utilise toutefois Gulp pour créer mes fichiers jsx en javascript. 

Est-il possible de mettre cela en quelque sorte à l'intérieur de Gulp? Et si oui, comment puis-je vérifier que React s'exécute en mode de production?

Voici mon 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() {});
28
vgoklani

2017 - Edit: tous ceux qui essaient de configurer React dans Gulp pour un nouveau projet: utilisez simplement create-react-app


Étape I: Ajoutez ce qui suit à votre fichier gulpfile.js quelque part

gulp.task('apply-prod-environment', function() {
    process.env.NODE_ENV = 'production';
});

Étape II: _ Ajoutez-le à votre tâche par défaut (ou à la tâche que vous utilisez pour servir/créer votre application)

// before: 
// gulp.task('default',['browsersync','watch'], function() {});
// after:
   gulp.task('default',['apply-prod-environment', 'browsersync','watch'], function() {});

FACULTATIF: _ Si vous voulez être absolument CERTAIN que vous êtes en mode prod, vous pouvez créer la tâche légèrement améliorée suivante au lieu de celle de l'étape 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");
    }
});

Qui générera l'erreur suivante si NODE_ENV n'est jamais défini sur '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!!!!
29
Monarch Wadia

Semblable aux autres réponses, mais donne heureusement à quelqu'un un point de départ:

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'));
});

La principale différence est que je configure explicitement NODE_ENV avant de regrouper les bibliothèques du fournisseur. Les tâches Gulp ne sont pas garanties pour être exécutées dans l'ordre. 

Suis-je en mode production?

Si vous supprimez la ligne uglify (et la mémoire tampon précédente), vous remarquerez que les versions de développement et de production ont une taille presque identique et qu'elles correspondent au nombre de lignes.

La différence est que la version de production sera remplie de:

"production" !== "production" ? [show dev error] : [no nothing]

La plupart des minify'ers de bonne réputation (je crois) vont supprimer le code mort, tel que ci-dessus, ce qui donnera toujours le résultat faux. 

Mais vraiment comment puis-je dire?

La méthode la plus simple pour être sûr, serait d'aller à la console de votre application en cours d'exécution et tapez:

React.createClass.toString();

Le résultat devrait être:

"function (e){var t=function(e,t,n){this.__reactAutoBindMap&&c(this),"[....and more and more]

Si vous trouvez la classe createClass dans la source de réaction, vous verrez:

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);
      }

Notez que la sortie de la console passe directement à this.__reactAutobind, car vous utilisez le mode de production et que vous utilisez un minify'er, tous les warngins et les contrôles de «production»! == ont été ignorés. 

7
Chris

Pour définir React en mode de production, vous devez définir votre variable NODE_ENV en mode de production et modifier votre JS en tant qu’étape supplémentaire. 

Vous vous occupez déjà de l'euglification, pour définir votre variable NODE_ENV: 

  • Définissez la variable lors de l'exécution de la tâche gulp: 

NODE_ENV='production' gulp

  • OU définissez-le depuis l'intérieur de votre fichier gulp en faisant quelque chose comme ceci: 

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

1
Rakan Nimer

Malheureusement, aucune des réponses ci-dessus ne fonctionne, car la définition de process.env.NODE_ENV n'a aucun effet dans Browserify. Le paquet résultant contient toujours des références process.env.NODE_ENV et donc

  • Browserify ne va pas require() les modules de la version de production de React,
  • le minifier ne pourra pas supprimer le code mort, et
  • l'application sera toujours en cours d'exécution en mode débogage.

Ce n’est malheureusement pas le seul endroit où cette approche est proposée comme la bonne réponse :-(


La bonne approche peut être trouvée dans, par exemple.

Vous devez basculer la transformation envify sur une transformation globale, par exemple.

# note the "-g" instead of the usual "-t"
$ browserify ... -g [ envify --NODE_ENV production ] ....

ou en 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
    ...
0
Stefan Becker

Aussi, vous pouvez utiliser le moyen pratique avec 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/"));

Pour exécuter gulp en mode production:

gulp build --env=production
0
mnv