¿Es posible pasar una bandera a Gulp para que ejecute tareas de diferentes maneras?

369

Normalmente en Gulp las tareas se ven así:

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

¿Es posible pasar un indicador de línea de comando para tragar (eso no es una tarea) y hacer que ejecute tareas condicionalmente en función de eso? Por ejemplo

$ gulp my-task -a 1

Y luego en mi 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
fuente
11
Como se está ejecutando en el nodo, probablemente podría usar process.argvpara acceder a los argumentos de la línea de comandos.
zzzzBov

Respuestas:

528

Gulp no ofrece ningún tipo de utilidad para eso, pero puede usar uno de los muchos analizadores de argumentos de comando. Me gusta yargs. Debiera ser:

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

También puede combinarlo gulp-ifpara canalizar condicionalmente la transmisión, muy útil para la creación de desarrollo frente a producción:

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

Y llama con gulp my-js-tasko gulp my-js-task --production.

Caio Cunha
fuente
45
Esto debería mencionarse de alguna manera @ el gulp oficial gulp, ¡cosas esenciales!
Max
2
Este video explica cómo lograr esto sin hilos: youtube.com/watch?v=gRzCAyNrPV8
plankguy
99
Hola @plankguy, el video es muy bueno. Gracias. Muestra cómo analizar las variables de entorno a mano, sin ninguna lib. Una pequeña diferencia es que el video trata sobre variables de entorno , mientras que el ejemplo anterior trata sobre argumentos de línea de comandos , donde Yargs es otra herramienta que ayuda a simplificar el consumo al abstraer el análisis de variables.
Caio Cunha
12
Si lo usa, npm run gulpentonces debe usarlo como npm run gulp -- --production.
ivkremer
3
Esto se menciona @ the gulp github oficial (literalmente).
fracz
101

Editar

gulp-utilestá en desuso y debe evitarse, por lo que se recomienda usar minimist en su lugar, que gulp-utilya se usó.

Así que he cambiado algunas líneas en mi archivo para eliminar gulp-util:

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

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

Original

En mi proyecto uso la siguiente bandera:

gulp styles --theme literature

Gulp ofrece un objeto gulp.envpara eso. Está en desuso en las versiones más recientes, por lo que debe usar gulp-util para eso. Las tareas se ven así:

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

La configuración del entorno está disponible durante todas las subtareas. Así que también puedo usar esta bandera en la tarea de observación:

gulp watch --theme literature

Y mi tarea de estilos también funciona.

Ciao Ralf

RWAM
fuente
66
gulp.envestá en desuso , como puede ver en el mensaje de registro de la consola al ejecutarlo. Te piden que uses tu propio analizador y te sugieran yargso minimist.
Caio Cunha
2
Gracias @CaioToOn por tu pista. He actualizado mi respuesta y mi proyecto también;)
RWAM
44
Puedes acortar util.env.theme ? util.env.theme : 'main'a util.env.theme || 'main'. De todos modos +1.
Renan
99
gulp-utilutiliza la minimistbiblioteca para el análisis de argumentos de línea de comando. Entonces, si está utilizando gulp-util, no necesita una biblioteca adicional para ese propósito. Documento: github.com/substack/minimist
Rockallite
57

Aquí hay una receta rápida que encontré:

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

Referencia original (ya no está disponible): https://github.com/gulpjs/gulp/blob/master/docs/recipes/pass-params-from-cli.md

Alternativa con minimista

De Ref actualizado: 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
fuente
2
Ese enlace de receta parece desaparecido ahora. Hay otro que usa el paquete minimist en su lugar: pass-arguments-from-cli.md . Eso tiene sentido ya que el trago en sí usa minimist .
yuvilio
39

Hay una manera muy simple de hacer on/offbanderas sin analizar los argumentos. gulpfile.jses solo un archivo que se ejecuta como cualquier otro, por lo que puede hacer:

var flags = {
  production: false
};

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

Y use algo como gulp-ifejecutar condicionalmente un paso

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

La ejecución gulp buildproducirá un buen html, mientras que gulp production buildlo minimizará.

Emil Ivanov
fuente
2
Gran idea, ahorra usando hilos, he extendido esto al tener una tarea de 'preproducción' que establece los vars y luego 'producción' tiene una matriz de dependencia de ['construir', 'preproducción']. De esa manera, puede ejecutar 'producción de tragos'.
Keegan 82
¡Agradable! Estoy usando esto antes de configurar la transmisión, congulp.task('mytask', function() { if (flags.myflag ) { flaggedtask } else { unflaggedask } });
henry
Creo que esta es la mejor manera de hacerlo
gztomas el
@ Keegan'shairstyle82 Hice algo similar pero tuve que utilizar la secuencia de ejecución para asegurarme de que no había condiciones de carrera al establecer las propiedades de flags.
CalMlynarczyk
3
La desventaja de este método es que debe cambiar gulpfile.js cada vez que desee cambiar las variables de marca, en lugar de simplemente pasar argumentos al comando gulp en el terminal.
jbyrd
33

Si tiene algunos argumentos estrictos (¡ordenados!), Puede obtenerlos simplemente marcando process.argv.

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

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

Ejecutalo: gulp --env production

... sin embargo, creo que esto es demasiado estricto y no a prueba de balas. Entonces, jugueteé un poco ... y terminé con esta función de utilidad:

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

Come un nombre de argumento y buscará esto en process.argv. Si no se encuentra nada, se escupe null. De lo contrario, si no hay un siguiente argumento o si el siguiente argumento es un comando y no truese devuelve un valor (diferimos con un guión) . (Eso es porque la clave existe, pero simplemente no hay valor). Si todos los casos anteriores fallarán, el siguiente argumento-valor es lo que obtenemos.

> 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, suficiente por ahora ... Aquí hay un ejemplo simple usando 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"));
});

Ejecutarlo gulp --env production

yckart
fuente
el nombre del argumento debe tener el prefijo guión (es):, if (args[0] === '--env' && args[1] === 'production');al menos en el trago 3.8.11
piotr_cz
@yckart: probablemente debería agregar el require ('..') para getArg en su ejemplo de código.
jbyrd
7

Construí un complemento para inyectar parámetros desde la línea de comandos en la devolución de llamada de la tarea.

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

// gulp mytask --production

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

Si alguien encuentra un error o lo mejora, me complace fusionar los RP.

Stoeffel
fuente
4

Y si está utilizando typecript ( gulpfile.ts), haga esto para yargs(basándose en la excelente respuesta de @Caio Cunha https://stackoverflow.com/a/23038290/1019307 y otros comentarios anteriores):

Instalar en pc

npm install --save-dev yargs

typings install dt~yargs --global --save

.ts archivos

Agregue esto a los archivos .ts:

import { argv } from 'yargs';

...

  let debug: boolean = argv.debug;

Esto debe hacerse en cada archivo .ts individualmente (incluso los tools/tasks/projectarchivos que se importan engulpfile.ts/js ).

correr

gulp build.dev --debug

O debajo de npmpasar el argumento a tragar:

npm run build.dev -- --debug
HankCa
fuente
2

Pase argumentos desde la línea de comando

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

Luego corre tragando con:

$ gulp scripts --env development

Fuente

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

CLI gulp productionllama a mi tarea de producción y establece un indicador para cualquier condición.

Keegan 82
fuente
1

Queríamos pasar un archivo de configuración diferente para diferentes entornos - uno para la producción , dev y pruebas . Este es el código en el archivo 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;
}

Este es el código en el archivo 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);
    }

Y luego correrlo tragar --env=testing

Sara Inés Calderón
fuente
1

Ha pasado algún tiempo desde que se publicó esta pregunta, pero tal vez ayude a alguien.

Estoy usando GULP CLI 2.0.1 (instalado globalmente) y GULP 4.0.0 (instalado localmente) aquí es cómo lo hace sin ningún complemento adicional. Creo que el código se explica por sí mismo.

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;

Y correr desde la consola:

gulp availableTasks

Luego corre y ve las diferencias:

gulp availableTasks --verbose
TMMC
fuente