I never quite liked JavaScript building tools. Grunt always seemed way too complicated for the simple things I wanted to accomplish. Like concatenating files and minifying them. One of the first bash commands that any Linux user learns about is cat.

You can just cat a few files together and pipe them to a minifying script and be done. 5 lines of Bash maximum. Want to also include the build date in your JavaScript file as a header? Just run:

echo /* `date -R` */ > build.js

I think Grunt's highly declarative syntax was the real barrier here, since it prevented you from doing quick adjustments to the building pipeline.

This all changed with Gulp. Gulp promotes and imperative approach to building apps and it tries to stay simple and focused on its task.

Its syntax feels a lot like the Linux CLI. Commands are pipelined together in a very simple manner:

gulp.task('scripts', function() {
  return gulp.src(['js/*.js'])
    .pipe(uglify())
    .pipe(concat('build.min.js'))
    .pipe(gulp.dest('build/'));
});

Basically it reads files from an input directory, minifies, concatenates and puts the resulting file in the build/ directory.

Tasks can be created for any kind of task: linting the code, compiling lesscss files, watching files and recompiling them on change, etc.

The API

The Gulp API is very small, it only has a few commands. Most of which we already encountered in the code snippet above.

gulp.task

Declares a new Gulp task. You can also declare tasks which simply run a series of other tasks (dependencies).

gulp.watch

Watches files for changes. For example lesscss files.

gulp.src

Returns a readable NodeJS stream which can be piped inside the task. An array of files can also be passed to the src function. This is actually the most common use case. A feature of src is that it will read the provided files in order. This is significant for plugins such as less.

gulp.src.pipe

Pipes commands to the NodeJS stream. These commands can be gulp plugins such as: uglify, concat, less, etc. They can also be user defined functions. Many commands can take options (parameters).

gulp.dest

Writes the result to the destination. This does not happen immediately, but upon the completion of other piped commands.

Gulp makes extensive use of NodeJS streams. Files are read from the filesystem, entirely manipulated in memory, then written back to the filesystem. This might not seem like much, but Grunt used to create many small files for every intermediary result.
To achieve this Gulp uses vinyl, which creates virtual file objects.

The example gulpfile.js used in this article can be found in this git repo with plenty of comments.

Read more