I wanted to try gulp.js for a long time and as an exercise I migrated a personal project to using it. My only pain point was with asynchronous tasks.

# Dependent tasks

The main pain point I had migrating it was dependent tasks started before the completion of their dependencies. This was especially painful with clean tasks and made my first attempts to fail with:

var clean = require('gulp-clean');
var jsdoc = require('gulp-jsdoc');

gulp.task('clean-apidoc', function() {
  /* this is broken! */
  gulp.src('apidocs', { read: false })
    .pipe(clean());
});
gulp.task('apidoc', ['clean-apidoc'], function() {
  gulp.src(['src/README.md', 'src/**/*.js'])
    .pipe(jsdoc('apidocs'));
});

Both tasks actually ran concurrently and the clean task failed to delete the root folder since the apidoc one already added back files in the directory. The solution is pretty simple: return the processed stream for gulp to consider the task as asynchronous and wait for its actual completion before starting dependent ones.

gulp.task('clean-apidoc', function() {
  return gulp.src('apidocs', { read: false })
    .pipe(clean());
});
gulp.task('apidoc', ['clean-apidoc'], function() {
  return gulp.src(['src/README.md', 'src/**/*.js'])
    .pipe(jsdoc('apidocs'));
});

# Completion

I think one must always report asynchronous tasks as being asynchronous even though there is no dependent task to be run afer, because otherwise gulp reports the task as being finished even though it is not. For example with

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

gulp.task('lint', function() {
  /* this is broken! */
  gulp.src(['gulpfile.js', 'src/**/*.js', 'test/**/*.js'])
    .pipe(jshint())
    .pipe(jshint.reporter('default'));
});

the command line displays the error after telling it completed in a few microseconds

[gulp] Using gulpfile /home/mathieu/dev/mathsync/javascript/core/gulpfile.js
[gulp] Starting 'lint'...
[gulp] Finished 'lint' after 164 ms
/home/mathieu/dev/mathsync/javascript/core/src/arrayBufferSerialization.js: line 4, col 41, Strings must use singlequote.

By simply returning the stream

gulp.task('lint', function() {
  return gulp.src(['gulpfile.js', 'src/**/*.js', 'test/**/*.js'])
    .pipe(jshint())
    .pipe(jshint.reporter('default'));
});

gulp displays the error at the expected place and reports reasonnable time

[gulp] Using gulpfile /home/mathieu/dev/mathsync/javascript/core/gulpfile.js
[gulp] Starting 'lint'...
/home/mathieu/dev/mathsync/javascript/core/src/arrayBufferSerialization.js: line 4, col 41, Strings must use singlequote.

1 error
[gulp] Finished 'lint' after 837 ms

# Documentation

The issue actually boils down to documentation, most gulp plugins show of task examples in their README without returning the stream. So please if you write a gulp plugin mark all your asynchronous examples as being asynchronous so that users can copy/paste them. It is generally only about adding a return statement. And please if you spot a plugin with invalid documentation open a pull request.

# Misc

Apart from that, as many already reported it makes the build faster, though gulp is not the only one to praise here because two tasks used to each take longer than the whole build does now. Even if gulp may be faster by being parallel by default, plugins have also improved a lot.

I really like the shape of the resulting gulpfile.js, I find it easier to visually group related tasks and it is a bit shorter. When multiple tasks refer to the same set of files, I have been tempted to create a variable to respect DRY but it made the file look awkward so I made an exception to the rule here.