373

Normally in Gulp tasks look like this:

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

Is it possible to pass a command line flag to gulp (that's not a task) and have it run tasks conditionally based on that? For instance

$ gulp my-task -a 1

And then in my 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));
});
Sven Schoenung
  • 27,914
  • 8
  • 57
  • 63
asolberg
  • 5,992
  • 9
  • 29
  • 44
  • 11
    As it's running in node, you could probably use `process.argv` to access the command line arguments. – zzzzBov Apr 11 '14 at 22:35

11 Answers11

528

Gulp doesn't offer any kind of util for that, but you can use one of the many command args parsers. I like yargs. Should be:

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

You can also combine it with gulp-if to conditionally pipe the stream, very useful for dev vs. prod building:

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

And call with gulp my-js-task or gulp my-js-task --production.

Caio Cunha
  • 23,016
  • 6
  • 74
  • 73
  • 45
    This should be somehow mentioned @ the official gulp github, essential stuff! – Max Jul 17 '14 at 15:06
  • 2
    This, video explains how to achieve this without yargs: https://www.youtube.com/watch?v=gRzCAyNrPV8 – plankguy Oct 19 '14 at 22:56
  • 9
    Hi @plankguy, the video is very nice. Thanks. It shows how to parse the environment variables by hand, without any lib. A small difference is that the video is about *environment variables*, while the example above is about *command line arguments*, where Yargs is yet another tool that helps simplify the consumption by abstracting the variables parsing. – Caio Cunha Oct 30 '14 at 21:51
  • 1
    Incase anyone else is looking for how to do multiple conditions with gulp-if -------> `.pipe($.if(argv.prod, $.if('*.js', $.uglify()) ))` (where the $.if = gulpif) – am_ Mar 08 '15 at 13:43
  • 12
    If you use `npm run gulp` then you should use it like `npm run gulp -- --production`. – ivkremer Dec 06 '15 at 02:28
  • 3
    This is mentioned @ the [official gulp github](https://github.com/gulpjs/gulp/blob/master/docs/CLI.md#task-specific-flags) (literally). – fracz Jun 17 '16 at 19:10
  • You cannot use `gulpif(argv.production, ...` but instead you should use `gulpif(!!argv.production,...` to convert expected condition to boolean. – G. Ghez Nov 16 '16 at 16:31
102

Edit

gulp-util is deprecated and should be avoid, so it's recommended to use minimist instead, which gulp-util already used.

So I've changed some lines in my gulpfile to remove gulp-util:

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

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

Original

In my project I use the following flag:

gulp styles --theme literature

Gulp offers an object gulp.env for that. It's deprecated in newer versions, so you must use gulp-util for that. The tasks looks like this:

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

The environment setting is available during all subtasks. So I can use this flag on the watch task too:

gulp watch --theme literature

And my styles task also works.

Ciao Ralf

RWAM
  • 5,949
  • 3
  • 32
  • 41
  • 6
    [`gulp.env` is being deprecated](https://github.com/gulpjs/gulp/blob/master/CHANGELOG.md#35), as you can see by the console log message when running it. They ask you to use your own parser and suggest `yargs` or `minimist`. – Caio Cunha Apr 15 '14 at 18:51
  • 2
    Thanks @CaioToOn for your hint. I've updated my answer and my project too ;) – RWAM Apr 15 '14 at 19:01
  • 4
    You can shorten `util.env.theme ? util.env.theme : 'main'` to `util.env.theme || 'main'`. Anyway +1. – Geeky Guy Jun 08 '15 at 13:31
  • 9
    `gulp-util` utilizes `minimist` library for command line argument parsing. So if you're using `gulp-util`, you don't need an extra library for that purpose. Document: https://github.com/substack/minimist – Rockallite Jul 03 '15 at 03:09
58

Here's a quick recipe I found:

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

Original Ref (not available anymore): https://github.com/gulpjs/gulp/blob/master/docs/recipes/pass-params-from-cli.md

Alternative with minimist

From Updated Ref: 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
  • 1,199
  • 1
  • 15
  • 18
  • 2
    That recipe link seems gone now. There is another one that uses the minimist package instead: [pass-arguments-from-cli.md](https://github.com/gulpjs/gulp/blob/master/docs/recipes/pass-arguments-from-cli.md). That makes sense since gulp itself [uses minimist](https://github.com/gulpjs/gulp/blob/master/package.json#L27). – yuvilio Oct 01 '14 at 16:21
39

There's a very simple way to do on/off flags without parsing the arguments. gulpfile.js is just a file that's executed like any other, so you can do:

var flags = {
  production: false
};

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

And use something like gulp-if to conditionally execute a step

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

Executing gulp build will produce a nice html, while gulp production build will minify it.

Lukas Cenovsky
  • 5,130
  • 2
  • 26
  • 38
Emil Ivanov
  • 35,757
  • 11
  • 70
  • 90
  • 2
    Great idea, saves using yargs, I've extended this by having a 'pre-production' task that sets the vars and then 'production' has a dependency array of ['build','pre-production']. That way you can just run 'gulp production'. – Keegan 82 Jun 04 '15 at 13:39
  • Nice! I'm using this before setting the stream, with `gulp.task('mytask', function() { if (flags.myflag ) { flaggedtask } else { unflaggedask } });` – henry Apr 09 '16 at 18:40
  • I think this is the gulp way to do it – gztomas Jun 01 '16 at 15:00
  • @Keegan'shairstyle82 I did something similar but had to utilize [run-sequence](https://www.npmjs.com/package/run-sequence) to ensure there were no race conditions when setting properties of `flags`. – CalMlynarczyk Jun 09 '16 at 16:45
  • 3
    The disadvantage of this method is that you have to change gulpfile.js every time you want to change flag variables, rather than just passing arguments to the gulp command in the terminal. – jbyrd Oct 18 '16 at 17:34
  • Be warned that `gulp production build` will run tasks `production` and `build` in *parallel* by default, so this technique might be vulnerable to a race condition, however unlikely. Use `gulp production build --series` to clear the risk. – jfroy Nov 29 '18 at 15:13
33

If you've some strict (ordered!) arguments, then you can get them simply by checking process.argv.

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

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

Execute it: gulp --env production

...however, I think that this is tooo strict and not bulletproof! So, I fiddled a bit around... and ended up with this utility function:

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

It eats an argument-name and will search for this in process.argv. If nothing was found it spits out null. Otherwise if their is no next argument or the next argument is a command and not a value (we differ with a dash) true gets returned. (That's because the key exist, but there's just no value). If all the cases before will fail, the next argument-value is what we get.

> 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, enough for now... Here's a simple example using 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"));
});

Run it gulp --env production

yckart
  • 28,174
  • 7
  • 112
  • 121
  • argument name should be prefixed with dash(es): `if (args[0] === '--env' && args[1] === 'production');`, at least in gulp 3.8.11 – piotr_cz Jun 11 '15 at 10:57
  • @yckart - you should probably add the require('..') for getArg in your code example. – jbyrd Oct 18 '16 at 17:36
7

I built a plugin to inject parameters from the commandline into the task callback.

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

// gulp mytask --production

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

If someone finds a bug or has a improvement to it, I am happy to merge PRs.

stoeffel
  • 228
  • 2
  • 6
4

And if you are using typescript (gulpfile.ts) then do this for yargs (building on @Caio Cunha's excellent answer https://stackoverflow.com/a/23038290/1019307 and other comments above):

Install

npm install --save-dev yargs

typings install dt~yargs --global --save

.ts files

Add this to the .ts files:

import { argv } from 'yargs';

...

  let debug: boolean = argv.debug;

This has to be done in each .ts file individually (even the tools/tasks/project files that are imported into the gulpfile.ts/js).

Run

gulp build.dev --debug

Or under npm pass the arg through to gulp:

npm run build.dev -- --debug
HankCa
  • 7,927
  • 7
  • 55
  • 72
2

Pass arguments from the command line

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

Then run gulp with:

$ gulp scripts --env development

Source

HaNdTriX
  • 25,034
  • 10
  • 72
  • 80
2
var isProduction = (process.argv.indexOf("production")>-1);

CLI gulp production calls my production task and sets a flag for any conditionals.

Keegan 82
  • 264
  • 2
  • 11
1

We wanted to pass a different config file for different environments -- one for production, dev and testing. This is the code in the gulp file:

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

This is the code in the app.js file:

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

And then to run it gulp --env=testing

Aliaksandr Sushkevich
  • 7,264
  • 6
  • 29
  • 36
1

It has been some time since this question has been posted, but maybe it will help someone.

I am using GULP CLI 2.0.1 (installed globally) and GULP 4.0.0 (installed locally) here is how you do it without any additional plugin. I think the code is quite self-explanatory.

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;

And run from the console:

gulp availableTasks

Then run and see the differences:

gulp availableTasks --verbose
TMMC
  • 161
  • 1
  • 5