Is it possible to pass a flag to Gulp to have it run tasks in different ways?

Is it possible to pass a flag to Gulp to have it run tasks in different ways?

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

Solutions/Answers:

Solution 1:

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.

Solution 2:

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

Solution 3:

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

Solution 4:

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.

Solution 5:

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

Solution 6:

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.