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() {});
É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!!!!
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.
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:
NODE_ENV='production' gulp
gulp.task('set-production-env', function() {
return process.env.NODE_ENV = 'production';
});
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
require()
les modules de la version de production de React,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
...
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