Est-il possible de passer un drapeau à Gulp pour qu'il exécute les tâches de différentes manières?

369

Normalement, dans Gulp, les tâches ressemblent à ceci:

gulp.task('my-task', function() {
    return gulp.src(options.SCSS_SOURCE)
        .pipe(sass({style:'nested'}))
        .pipe(autoprefixer('last 10 version'))
        .pipe(concat('style.css'))
        .pipe(gulp.dest(options.SCSS_DEST));
});

Est-il possible de passer un drapeau de ligne de commande à gulp (ce n'est pas une tâche) et de lui faire exécuter des tâches conditionnellement sur cette base? Par exemple

$ gulp my-task -a 1

Et puis dans mon gulpfile.js:

gulp.task('my-task', function() {
        if (a == 1) {
            var source = options.SCSS_SOURCE;
        } else {
            var source = options.OTHER_SOURCE;
        }
        return gulp.src(source)
            .pipe(sass({style:'nested'}))
            .pipe(autoprefixer('last 10 version'))
            .pipe(concat('style.css'))
            .pipe(gulp.dest(options.SCSS_DEST));
});
asolberg
la source
11
Comme il s'exécute dans le nœud, vous pouvez probablement utiliser process.argvpour accéder aux arguments de la ligne de commande.
zzzzBov

Réponses:

528

Gulp n'offre aucun type d'utilisation pour cela, mais vous pouvez utiliser l'un des nombreux analyseurs d'arguments de commande. J'aime yargs. Devrait être:

var argv = require('yargs').argv;

gulp.task('my-task', function() {
    return gulp.src(argv.a == 1 ? options.SCSS_SOURCE : options.OTHER_SOURCE)
        .pipe(sass({style:'nested'}))
        .pipe(autoprefixer('last 10 version'))
        .pipe(concat('style.css'))
        .pipe(gulp.dest(options.SCSS_DEST));
});

Vous pouvez également le combiner avec gulp-ifpour canaliser conditionnellement le flux, très utile pour la construction de dev vs prod:

var argv = require('yargs').argv,
    gulpif = require('gulp-if'),
    rename = require('gulp-rename'),
    uglify = require('gulp-uglify');

gulp.task('my-js-task', function() {
  gulp.src('src/**/*.js')
    .pipe(concat('out.js'))
    .pipe(gulpif(argv.production, uglify()))
    .pipe(gulpif(argv.production, rename({suffix: '.min'})))
    .pipe(gulp.dest('dist/'));
});

Et appelez avec gulp my-js-taskou gulp my-js-task --production.

Caio Cunha
la source
45
Cela devrait être mentionné d'une manière ou d'une autre sur le github officiel de gulp, des trucs essentiels!
Max
2
Cette vidéo explique comment y parvenir sans yargs: youtube.com/watch?v=gRzCAyNrPV8
plankguy
9
Salut @plankguy, la vidéo est très sympa. Merci. Il montre comment analyser les variables d'environnement à la main, sans aucune lib. Une petite différence est que la vidéo concerne les variables d'environnement , tandis que l'exemple ci-dessus concerne les arguments de ligne de commande , où Yargs est un autre outil qui aide à simplifier la consommation en faisant abstraction de l'analyse des variables.
Caio Cunha
12
Si vous utilisez, npm run gulpvous devez l'utiliser comme npm run gulp -- --production.
ivkremer
3
Ceci est mentionné @ le github officiel de gulp (littéralement).
fracz
101

Éditer

gulp-utilest obsolète et devrait être évité, il est donc recommandé d'utiliser minimist à la place, qui était gulp-utildéjà utilisé.

J'ai donc changé certaines lignes de mon gulpfile pour les supprimer gulp-util:

var argv = require('minimist')(process.argv.slice(2));

gulp.task('styles', function() {
  return gulp.src(['src/styles/' + (argv.theme || 'main') + '.scss'])
    
});

Original

Dans mon projet, j'utilise le drapeau suivant:

gulp styles --theme literature

Gulp propose un objet gulp.envpour cela. Il est déconseillé dans les versions plus récentes, vous devez donc utiliser gulp-util pour cela. Les tâches ressemblent à ceci:

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

gulp.task('styles', function() {
  return gulp.src(['src/styles/' + (util.env.theme ? util.env.theme : 'main') + '.scss'])
    .pipe(compass({
        config_file: './config.rb',
        sass   : 'src/styles',
        css    : 'dist/styles',
        style  : 'expanded'

    }))
    .pipe(autoprefixer('last 2 version', 'safari 5', 'ie 8', 'ie 9', 'ff 17', 'opera 12.1', 'ios 6', 'android 4'))
    .pipe(livereload(server))
    .pipe(gulp.dest('dist/styles'))
    .pipe(notify({ message: 'Styles task complete' }));
});

Le paramètre d'environnement est disponible pendant toutes les sous-tâches. Je peux donc aussi utiliser ce drapeau sur la tâche de surveillance:

gulp watch --theme literature

Et ma tâche de styles fonctionne également.

Ciao Ralf

RWAM
la source
6
gulp.envest obsolète , comme vous pouvez le voir dans le message du journal de la console lors de son exécution. Ils vous demandent d'utiliser votre propre analyseur et suggèrent yargsou minimist.
Caio Cunha
2
Merci @CaioToOn pour votre conseil. J'ai mis à jour ma réponse et mon projet aussi;)
RWAM
4
Vous pouvez raccourcir util.env.theme ? util.env.theme : 'main'à util.env.theme || 'main'. Quoi qu'il en soit +1.
Renan
9
gulp-utilutilise la minimistbibliothèque pour l'analyse des arguments de la ligne de commande. Donc, si vous utilisez gulp-util, vous n'avez pas besoin d'une bibliothèque supplémentaire à cet effet. Document: github.com/substack/minimist
Rockallite
57

Voici une recette rapide que j'ai trouvée:

gulpfile.js

var gulp   = require('gulp');

// npm install gulp yargs gulp-if gulp-uglify
var args   = require('yargs').argv;
var gulpif = require('gulp-if');
var uglify = require('gulp-uglify');

var isProduction = args.env === 'production';

gulp.task('scripts', function() {
  return gulp.src('**/*.js')
    .pipe(gulpif(isProduction, uglify())) // only minify if production
    .pipe(gulp.dest('dist'));
});

CLI

gulp scripts --env production

Ref d'origine (plus disponible): https://github.com/gulpjs/gulp/blob/master/docs/recipes/pass-params-from-cli.md

Alternative avec minimist

De la référence mise à jour: https://github.com/gulpjs/gulp/blob/master/docs/recipes/pass-arguments-from-cli.md

gulpfile.js

// npm install --save-dev gulp gulp-if gulp-uglify minimist

var gulp = require('gulp');
var gulpif = require('gulp-if');
var uglify = require('gulp-uglify');

var minimist = require('minimist');

var knownOptions = {
  string: 'env',
  default: { env: process.env.NODE_ENV || 'production' }
};

var options = minimist(process.argv.slice(2), knownOptions);

gulp.task('scripts', function() {
  return gulp.src('**/*.js')
    .pipe(gulpif(options.env === 'production', uglify())) // only minify if production
    .pipe(gulp.dest('dist'));
});

CLI

gulp scripts --env production
AEQ
la source
2
Ce lien de recette semble maintenant disparu. Il y en a un autre qui utilise le paquet minimist à la place: pass-arguments-from-cli.md . Cela a du sens puisque gulp utilise lui-même minimist .
yuvilio
39

Il existe un moyen très simple de faire des on/offdrapeaux sans analyser les arguments. gulpfile.jsest juste un fichier exécuté comme un autre, vous pouvez donc faire:

var flags = {
  production: false
};

gulp.task('production', function () {
  flags.production = true;
});

Et utilisez quelque chose comme gulp-ifpour exécuter conditionnellement une étape

gulp.task('build', function () {
  gulp.src('*.html')
    .pipe(gulp_if(flags.production, minify_html()))
    .pipe(gulp.dest('build/'));
});

L'exécution gulp buildproduira un joli html, tandis que gulp production buildle réduira.

Emil Ivanov
la source
2
Excellente idée, enregistre à l'aide de yargs, j'ai étendu cela en ayant une tâche de «pré-production» qui définit les vars, puis «production» a un tableau de dépendances de [«build», «pré-production»]. De cette façon, vous pouvez simplement exécuter la «production de gorgée».
Keegan 82
Agréable! J'utilise ceci avant de définir le flux, avecgulp.task('mytask', function() { if (flags.myflag ) { flaggedtask } else { unflaggedask } });
henry
Je pense que c'est la meilleure façon de le faire
gztomas
@ Keegan'shairstyle82 J'ai fait quelque chose de similaire mais j'ai dû utiliser la séquence d' exécution pour m'assurer qu'il n'y avait pas de conditions de course lors de la définition des propriétés de flags.
CalMlynarczyk
3
L'inconvénient de cette méthode est que vous devez modifier gulpfile.js à chaque fois que vous souhaitez modifier des variables d'indicateur, plutôt que de simplement passer des arguments à la commande gulp dans le terminal.
jbyrd
33

Si vous avez des arguments stricts (ordonnés!), Vous pouvez les obtenir simplement en les vérifiant process.argv.

var args = process.argv.slice(2);

if (args[0] === "--env" && args[1] === "production");

L'exécuter: gulp --env production

... cependant, je pense que c'est trop strict et pas à l'épreuve des balles! Donc, j'ai tripoté un peu ... et je me suis retrouvé avec cette fonction utilitaire:

function getArg(key) {
  var index = process.argv.indexOf(key);
  var next = process.argv[index + 1];
  return (index < 0) ? null : (!next || next[0] === "-") ? true : next;
}

Il mange un nom d'argument et le recherchera dans process.argv. Si rien n'est trouvé, ça crache null. Sinon, s'il n'y a pas d'argument suivant ou si l'argument suivant est une commande et qu'aucune valeur (nous différons avec un tiret) n'est truerenvoyée. (C'est parce que la clé existe, mais il n'y a tout simplement aucune valeur). Si tous les cas précédents échouent, la valeur d'argument suivante est celle que nous obtenons.

> gulp watch --foo --bar 1337 -boom "Foo isn't equal to bar."

getArg("--foo") // => true
getArg("--bar") // => "1337"
getArg("-boom") // => "Foo isn't equal to bar."
getArg("--404") // => null

Ok, assez pour l'instant ... Voici un exemple simple utilisant gulp :

var gulp = require("gulp");
var sass = require("gulp-sass");
var rename = require("gulp-rename");

var env = getArg("--env");

gulp.task("styles", function () {
  return gulp.src("./index.scss")
  .pipe(sass({
    style: env === "production" ? "compressed" : "nested"
  }))
  .pipe(rename({
    extname: env === "production" ? ".min.css" : ".css"
  }))
  .pipe(gulp.dest("./build"));
});

Exécuter gulp --env production

yckart
la source
le nom de l'argument doit être préfixé par un tiret (es) if (args[0] === '--env' && args[1] === 'production');:, au moins dans gulp 3.8.11
piotr_cz
@yckart - vous devriez probablement ajouter le require ('..') pour getArg dans votre exemple de code.
jbyrd
7

J'ai construit un plugin pour injecter des paramètres de la ligne de commande dans le rappel de tâche.

gulp.task('mytask', function (production) {
  console.log(production); // => true
});

// gulp mytask --production

https://github.com/stoeffel/gulp-param

Si quelqu'un trouve un bogue ou a une amélioration, je suis heureux de fusionner les PR.

stoeffel
la source
4

Et si vous utilisez tapuscript ( gulpfile.ts), faites-le pour yargs(en vous appuyant sur l'excellente réponse de @Caio Cunha https://stackoverflow.com/a/23038290/1019307 et d'autres commentaires ci-dessus):

Installer

npm install --save-dev yargs

typings install dt~yargs --global --save

.ts des dossiers

Ajoutez ceci aux fichiers .ts:

import { argv } from 'yargs';

...

  let debug: boolean = argv.debug;

Cela doit être fait dans chaque fichier .ts individuellement (même les tools/tasks/projectfichiers qui sont importés dans le gulpfile.ts/js).

Courir

gulp build.dev --debug

Ou sous npmpasser l'argument à gorgée:

npm run build.dev -- --debug
HankCa
la source
2

Passer des arguments depuis la ligne de commande

// npm install --save-dev gulp gulp-if gulp-uglify minimist

var gulp = require('gulp');
var gulpif = require('gulp-if');
var uglify = require('gulp-uglify');

var minimist = require('minimist');

var knownOptions = {
  string: 'env',
  default: { env: process.env.NODE_ENV || 'production' }
};

var options = minimist(process.argv.slice(2), knownOptions);

gulp.task('scripts', function() {
  return gulp.src('**/*.js')
    .pipe(gulpif(options.env === 'production', uglify())) // only minify in production
    .pipe(gulp.dest('dist'));
});

Exécutez ensuite gulp avec:

$ gulp scripts --env development

La source

HaNdTriX
la source
2
var isProduction = (process.argv.indexOf("production")>-1);

CLI gulp productionappelle ma tâche de production et définit un indicateur pour toutes les conditions.

Keegan 82
la source
1

Nous voulions passer un fichier de configuration différent pour différents environnements - un pour la production , dev et test . Voici le code du fichier gulp:

//passing in flag to gulp to set environment
//var env = gutil.env.env;

if (typeof gutil.env.env === 'string') {
  process.env.NODE_ENV = gutil.env.env;
}

Voici le code du fichier app.js:

  if(env === 'testing'){
      var Config = require('./config.testing.js');
      var Api = require('./api/testing.js')(Config.web);
    }
    else if(env === 'dev'){
       Config = require('./config.dev.js');
        Api = require('./api/dev.js').Api;
    }
    else{
       Config = require('./config.production.js');
       Api = require('./api/production.js')(Config.web);
    }

Et puis pour le faire avaler --env=testing

Sara Inés Calderón
la source
1

Cela fait un certain temps que cette question n'a pas été publiée, mais peut-être que cela aidera quelqu'un.

J'utilise GULP CLI 2.0.1 (installé globalement) et GULP 4.0.0 (installé localement) voici comment vous le faites sans plugin supplémentaire. Je pense que le code est assez explicite.

var cp = require('child_process'), 
{ src, dest, series, parallel, watch } = require('gulp');

// == availableTasks: log available tasks to console
function availableTasks(done) {
  var command = 'gulp --tasks-simple';
  if (process.argv.indexOf('--verbose') > -1) {
    command = 'gulp --tasks';
  }
  cp.exec(command, function(err, stdout, stderr) {
    done(console.log('Available tasks are:\n' + stdout));
  });
}
availableTasks.displayName = 'tasks';
availableTasks.description = 'Log available tasks to console as plain text list.';
availableTasks.flags = {
  '--verbose': 'Display tasks dependency tree instead of plain text list.'
};
exports.availableTasks = availableTasks;

Et exécutez à partir de la console:

gulp availableTasks

Ensuite, exécutez et voyez les différences:

gulp availableTasks --verbose
TMMC
la source