É possível passar um sinalizador para o Gulp para que ele execute tarefas de maneiras diferentes?

369

Normalmente, no Gulp, as tarefas são assim:

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

É possível passar um sinalizador de linha de comando para o gulp (isso não é uma tarefa) e executar tarefas condicionalmente com base nisso? Por exemplo

$ gulp my-task -a 1

E então no meu 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
fonte
11
Como está sendo executado no nó, você provavelmente poderia usar process.argvpara acessar os argumentos da linha de comando.
precisa saber é o seguinte

Respostas:

528

O Gulp não oferece nenhum tipo de utilitário para isso, mas você pode usar um dos muitos analisadores de comandos args. Eu gosto yargs. Deveria estar:

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

Você também pode combiná-lo com gulp-ifo canal condicional do fluxo, muito útil para a criação de desenvolvedores vs. produtos:

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

E ligue com gulp my-js-taskou gulp my-js-task --production.

Caio Cunha
fonte
45
Isso deve ser mencionado de alguma forma @ no gulp oficial github, coisas essenciais!
Max
2
Este, vídeo explica como conseguir isso sem yargs: youtube.com/watch?v=gRzCAyNrPV8
plankguy
9
Oi @plankguy, o vídeo é muito bom. Obrigado. Ele mostra como analisar as variáveis ​​de ambiente manualmente, sem nenhuma lib. Uma pequena diferença é que o vídeo trata de variáveis ​​de ambiente , enquanto o exemplo acima trata de argumentos de linha de comando , em que Yargs é outra ferramenta que ajuda a simplificar o consumo, abstraindo as variáveis ​​analisadas.
Caio Cunha
12
Se você usar npm run gulp, você deve usá-lo como npm run gulp -- --production.
ivkremer
3
Isso é mencionado no gulp github oficial (literalmente).
Fracz 17/06/2016
101

Editar

gulp-utilfoi descontinuado e deve ser evitado; portanto, é recomendável usar o minimist , que gulp-utiljá foi usado.

Então, eu mudei algumas linhas no meu gulpfile para remover gulp-util:

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

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

Original

No meu projeto, eu uso o seguinte sinalizador:

gulp styles --theme literature

Gulp oferece um objeto gulp.envpara isso. Ele foi descontinuado nas versões mais recentes, então você deve usar o gulp-util para isso. As tarefas são assim:

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

A configuração do ambiente está disponível durante todas as subtarefas. Para que eu possa usar esse sinalizador também na tarefa de observação:

gulp watch --theme literature

E a minha tarefa de estilos também funciona.

Ciao Ralf

RWAM
fonte
6
gulp.envestá sendo preterido , como você pode ver pela mensagem de log do console ao executá-lo. Eles pedem que você use seu próprio analisador e sugira yargsou minimist.
Caio Cunha
2
Obrigado @CaioToOn pela sua dica. Eu atualizei a minha resposta e meu projeto também;)
RWAM
4
Você pode reduzir util.env.theme ? util.env.theme : 'main'para util.env.theme || 'main'. Enfim +1.
Renan
9
gulp-utilutiliza minimistbiblioteca para análise de argumento de linha de comando. Portanto, se você estiver usando gulp-util, não precisará de uma biblioteca extra para esse fim. Documento: github.com/substack/minimist
Rockallite
57

Aqui está uma receita rápida que encontrei:

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 original (não está mais disponível): https://github.com/gulpjs/gulp/blob/master/docs/recipes/pass-params-from-cli.md

Alternativa com minimist

Da atualização atualizada: 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
fonte
2
Esse link da receita parece ter desaparecido agora. Há outro que usa o pacote minimist : pass-arguments-from-cli.md . Isso faz sentido, já que o próprio gole usa minimista .
Yuvilio 01/10
39

Existe uma maneira muito simples de fazer on/offsinalizadores sem analisar os argumentos. gulpfile.jsé apenas um arquivo que é executado como outro qualquer, então você pode fazer:

var flags = {
  production: false
};

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

E use algo como gulp-ifpara executar condicionalmente uma etapa

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

A execução gulp buildproduzirá um bom html, enquanto gulp production buildo minificará.

Emil Ivanov
fonte
2
Ótima idéia, economize usando yargs, estendi isso ao ter uma tarefa de 'pré-produção' que define os vars e, em seguida, 'produção' tem uma matriz de dependência de ['build', 'pré-produção']. Dessa forma, você pode simplesmente executar 'gulp production'.
Keegan 82
Agradável! Estou usando este antes de definir o fluxo, comgulp.task('mytask', function() { if (flags.myflag ) { flaggedtask } else { unflaggedask } });
henry
Eu acho que este é o caminho gole de fazê-lo
gztomas
@ Keegan'shairstyle82 Fiz algo semelhante, mas tive que utilizar a sequência de execução para garantir que não houvesse condições de corrida ao definir as propriedades de flags.
precisa saber é o seguinte
3
A desvantagem desse método é que você precisa alterar o gulpfile.js toda vez que quiser alterar as variáveis ​​de flag, em vez de apenas passar argumentos para o comando gulp no terminal.
jbyrd
33

Se você possui alguns argumentos estritos (ordenados!), Pode obtê-los simplesmente verificando process.argv.

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

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

Execute: gulp --env production

... no entanto, acho que isso é muito estrito e não à prova de balas! Então, eu brinquei um pouco ... e acabei com esta função de utilitário:

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

Ele usa um nome de argumento e o procurará em process.argv. Se nada foi encontrado, ele cospe null. Caso contrário, se não houver um próximo argumento ou o próximo argumento for um comando e não um valor (diferimos com um traço) trueserá retornado. (Isso ocorre porque a chave existe, mas simplesmente não há valor). Se todos os casos anteriores falharem, o próximo valor de argumento é o que obtemos.

> 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, chega por enquanto ... Aqui está um exemplo simples 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"));
});

Executá-lo gulp --env production

yckart
fonte
nome de argumento deve ser prefixado com traço (es): if (args[0] === '--env' && args[1] === 'production');, pelo menos em gole 3.8.11
piotr_cz
@ yckart - você provavelmente deve adicionar o require ('..') para getArg no seu exemplo de código.
jbyrd
7

Eu construí um plug-in para injetar parâmetros da linha de comando no retorno de chamada da tarefa.

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

// gulp mytask --production

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

Se alguém encontrar um bug ou tiver uma melhoria, fico feliz em mesclar PRs.

Stoeffel
fonte
4

E se você estiver usando o typescript ( gulpfile.ts), faça isso para yargs(com base na excelente resposta de @Caio Cunha https://stackoverflow.com/a/23038290/1019307 e outros comentários acima):

Instalar

npm install --save-dev yargs

typings install dt~yargs --global --save

.ts arquivos

Adicione isso aos arquivos .ts:

import { argv } from 'yargs';

...

  let debug: boolean = argv.debug;

Isso deve ser feito em cada arquivo .ts individualmente (mesmo nos tools/tasks/projectarquivos importados para o gulpfile.ts/js).

Corre

gulp build.dev --debug

Ou então, npmpasse o argumento até gulp:

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

Passar argumentos da linha 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'));
});

Em seguida, execute gulp com:

$ gulp scripts --env development

Fonte

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

A CLI gulp productionchama minha tarefa de produção e define um sinalizador para quaisquer condicionais.

Keegan 82
fonte
1

Queríamos para passar um arquivo de configuração diferente para ambientes diferentes - um para produção , dev e teste . Este é o código no arquivo 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 é o código no arquivo 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);
    }

E então para executá-lo gole --env=testing

Sara Inés Calderón
fonte
1

Já faz algum tempo desde que esta pergunta foi publicada, mas talvez ajude alguém.

Estou usando o GULP CLI 2.0.1 (instalado globalmente) e o GULP 4.0.0 (instalado localmente). Aqui está como você faz isso sem nenhum plug-in adicional. Eu acho que o código é bastante auto-explicativo.

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;

E execute a partir do console:

gulp availableTasks

Em seguida, execute e veja as diferenças:

gulp availableTasks --verbose
TMMC
fonte