Gulp – tutorial

gulp.js

Gulp is a streaming build system (aka task runner). It contains plugins, which allows you to run tasks such as TypeScript to JavaScript compilation, Less to CSS compilation, bundling, minification, running you own scripts, and much, much more.

Installation

Required: npm (Node Packaged Modules). You can install it with Chocolatey:

cinst nodejs

When you have npm, you are good to go and install Gulp:

npm install -g gulp

After installation, localize “gulp.cmd” file, and add its location to your PATH. Location depends on the way how you installed nodejs. On my one machine, where I installed nodejs using the installer, it is in C:\Users\jjed\AppData\Roaming\npm directory. On my other machine, where I installed nodejs from Chocolatey, it is in C:\ProgramData\chocolatey\lib\nodejs.commandline.0.10.31\tools. I recommend you Everything Search Engine not only for this task, but for searching all kind of files on your machine. It is ridiculously fast, and when you pin it to your task bar as the first item, you can invoke it with WIN+1.

I wish npm installation did this work (adding gulp to PATH) automatically.

Gulp Hello World

Open the Console (I recommend ConEmu as you Console on Windows), and cd into your project directory (for now it can be even empty directory).

From your project root directory run:

npm install --save-dev gulp

Create gulpfile.js file in the root of your project:

var gulp = require('gulp');

gulp.task('default', function () {
  console.log("Hello, world!");
});

Run gulp:

gulp

You should see the following result (with different time stamps and path, probably):

[21:45:32] Using gulpfile C:\dev\myproj\gulpfile.js
[21:45:32] Starting 'default'...
Hello, world!
[21:45:32] Finished 'default' after 141 µs

The default task is invoked when you run gulp.js without any arguments. You can run other tasks from default task. Below file contains hello task, and invoke it from the default task:

var gulp = require('gulp');

gulp.task('hello', function () {
  console.log("Hello, world!");
});

gulp.task('default', ['hello']);

The result of gulp run is a little bit different now:

[21:49:21] Using gulpfile C:\dev\myproj\gulpfile.js
[21:49:21] Starting 'hello'...
Hello, world!
[21:49:21] Finished 'hello' after 210 µs
[21:49:21] Starting 'default'...
[21:49:21] Finished 'default' after 8.21 µs

Using Gulp to compile TypeScript files ‘on change’

Install TypeScript (if you do not have it installed already):

npm install -g typescript

Make sure tsc is in your path.

Install TypeScript compiler for gulp.js (from your project root directory):

npm install --save-dev gulp-tsc

Create TypeScript directory, and cd into it:

mkdir TypeScript
cd TypeScript

Create simple hello.ts file:

function greeter(person: string) {
    return "Hello, " + person;
}

var user = "Anders Hejlsberg";

console.log(greeter(user));

Go to root directory of your project and create js directory (it will be output directory for generated JavaScript files):

mkdir js

Modify gulpfile.js:

var gulp = require('gulp'),
	typescript = require('gulp-tsc');

gulp.task('typescript-compile', function(){
  return gulp.src(['TypeScript/*.ts'])
    .pipe(typescript())
    .pipe(gulp.dest('js/'));
});

gulp.task('watch', function () {
  gulp.watch('TypeScript/*.ts', ['typescript-compile']);
});

gulp.task('default', ['typescript-compile', 'watch']);

Once you run gulp it will compile all TypeScript files from TypeScript directory to js directory. Furthermore, Gulp will not suspend, but it will watch all .ts files under TypeScript directory, and will recompile them every time you change and save some of them. Try it!

Prevent gulp.js from crashing by handling errors

You can notice that if some of your TypeScript files cause compilation error (e.g., because of syntax error) then gulp crashes.

In order to avoid it, you can add simple error handling function (errorLog) to gulp.js file, and call it in the typescript-compile task pipeline:

var gulp = require('gulp'),
	typescript = require('gulp-tsc');

function errorLog (error) {
  console.error.bind(error);
  this.emit('end');
}

gulp.task('typescript-compile', function(){
  return gulp.src(['TypeScript/*.ts'])
    .pipe(typescript())
    .on('error', errorLog)
    .pipe(gulp.dest('js/'));
});

gulp.task('watch', function () {
  gulp.watch('TypeScript/*.ts', ['typescript-compile']);
});

gulp.task('default', ['typescript-compile', 'watch']);

Now, Gulp will not crash, but display compilation error, and recompile files after next file change.

Using gulp.js to run batch/bash script

Let assume that you want to run some script (batch file on Windows, or bash script on Unix) after TypeScript files compilation.

First, we need to install gulp-shell plugin:

npm install gulp-shell

To keep it simple, our script will only output text “TypeScript compilation done” to the console.

Create file build.cmd in your project root directory:

echo "TypeScript compilation done"

And modify gulpfile.js:

var gulp = require('gulp'),
  run = require('gulp-shell'),
  typescript = require('gulp-tsc');

function errorLog (error) {
  console.error.bind(error);
  this.emit('end');
}

gulp.task('typescript-compile', function(){
  return gulp.src(['TypeScript/*.ts'])
    .pipe(typescript())
    .on('error', errorLog)
    .pipe(gulp.dest('js/'))
    .pipe(shell(['build.cmd']));
});

gulp.task('watch', function () {
  gulp.watch('TypeScript/*.ts', ['typescript-compile']);
});

gulp.task('default', ['typescript-compile', 'watch']);

In real-life you may want to copy all compiled files to some other directory, or do some other “your project specific” task.

Using gulp-shell you can run any command, or set of commands (concatenating them with ‘&‘ on Windows, or ‘&&‘ on Unix), e.g.:

shell(['cd c:/dev/myproj/src & build']);

Summary

Gulp is very handful tool. However it is not the only one. Its main rival is Grunt.js. Actually, Gulp was inspired by Grunt. Most of people (based on my research) prefer Gulp over Grunt. Main argument: it allows to stream results (run multiple operations on set of files), and it is less verbose (allows to do more with less configuration). Check Grunt vs Gulp comparison in this blog post, and this Steve Sanderson’s talk (starting from 30:50).

To get more of Gulp check Getting Started With Gulp, Learning Gulp, and gulp documentation.

Are you using Gulp or Grunt, or some other task runner?

EDIT: I updated the post with return statements in tasks. This informs task system that particular task is async, and prevents from occasional crashes when called from watch task.