Gulp — The streaming build system

I’ve recently wrote a post about Bower, how to add and maintain your dependencies. In connection to that I though it would be obvious to write a follow-up on how to build and manage your dependencies — And for this I found Gulp to be a really awesome tool!

What is Gulp?

Gulp basically works a set of “tasks” which describe what to do with your dependencies once you’ve included them in your project (for example using Bower) … Say you have a bunch of javascript files and that you would like to combine into one file — This could be one task in Gulp.

Another could be that you would like to minify the combined javascript file … and the same could be true for your CSS files.

You might also want to move around files from a source- to production-destination, these kind of tasks can all be handled by Gulp through a single configuration file and executed by one single command!

How does Gulp work?

Gulp works by execution tasks defined in a configuration file named gulpfile.js.

Each task is basically defined as an anonymous function which is executed asynchronously (hence the streaming part of the title). You can name your tasks and make them more synchronously by telling Gulp that one task depend on another task to finish before starting.

In the end Gulp will start by executing the task named “default” and then it’s up to you to explain what subtask(s) this should include.

Say you have 2 tasks, one for concatenating your CSS files into one, lets name it “concat-css”, and another task for minifying this concatenated file, which we named “minify-css”. You would then setup your “default” task like this (we will get into the detail later):

gulp.task('default', ['concat-css', 'minify-css']);

Now concatenation and minifying doesn’t come with Gulp out of the box. But as Gulp is simply another Node package, Gulp is able to require and use other Node packages.

You would defined all your required packages in the top of your gulpfile like so:

var gulp = require('gulp');
    concat = require('gulp-concat'),
    minifyCSS = require('gulp-minify-css');

As with any other Node package you should install the package in your project before being able to use it.

Installing Gulp (and other Node packages)

To get started you would install Gulp into your project like so:

npm install gulp

You can always search for other Node packages from npmjs.org. To complete the example above, you would want to install the following 2 packages as well:

npm install gulp-concat
npm install gulp-minify-css

Using Gulp

Right, so we’ve now installed Gulp and 2 other packages. We’ve require the packages in our Gulpfile and so we want our default gulp task to depend on 2 other task to run. Now let’s go a bit more into details on how we define these tasks.

The first task was to concatenate our CSS files. This we can write like this:

gulp.task('concat-css', function() {
    return gulp.src(['css1.css', 'css2.css'])
        .pipe(concat('style.css'))
        .pipe(gulp.dest('.'));
});

A few things to notice …

  1. We have name the task “concat-css”
  2. We perform work on an array of css-files. This could actually be defined as an expression as well: *.css
  3. We can pipe our resources from one method to another using the .pipe method
  4. We use the “gulp-concat” package when calling “concat” because that’s what we called the variable we required the packed to, in the top of the file. Here we tell gulp-concat to concatenate the source-files css1.css and css2.css into one file names style.css
  5. We return the entire result as a stream which can be handled further by other tasks

The second task looks very similar:

gulp.task('minify-css', ['concat-css'], function() {
    return gulp.src('style.css')
        .pipe(minifyCSS())
        .pipe(gulp.dest('.'));
});

As above, we’ve named the task “minify-css”, but we’ve also set this task to depend on the “concat-css” task to be run before starting this one. This task takes the concatenated file style.css as source and pipes it into the gulp CSS “gulp-minify-css”. Finally we write the result to disk.

By now the “default” task explained above should make a lot more sense, yes!? … The entire gulpfile.js looks like this:

var gulp = require('gulp');
    concat = require('gulp-concat'),
    minifyCSS = require('gulp-minify-css');

gulp.task('concat-css', function() {
    return gulp.src(['css1.css', 'css2.css'])
        .pipe(concat('style.css'))
        .pipe(gulp.dest('.'));
});

gulp.task('minify-css', ['concat-css'], function() {
    return gulp.src('style.css')
        .pipe(minifyCSS())
        .pipe(gulp.dest('.'));
});

gulp.task('default', ['concat-css', 'minify-css']);

When you have this, all you need to run in order to execute all task is simple: gulp

You can also run the individual task by referencing the task name gulp concat-css or gulp minify-css … as you will notice, any tasks depending on other, will run the depending tasks first.