Gulp – super simple workflow automator

Lately I’ve switched to Gulp from Grunt in my various pet projects. Why you ask? Because it’s simpler, faster and focus on code over configuration. I like code! In this post I will give a brief introduction to Gulp and share a simple workflow which is a great start when beginning to use Gulp.

gulp

Quick intro to Gulp

Gulp, same as Grunt, is a task runner for javascript that uses Node.js to run. The reason to use a task runner is to automate time consuming but important tasks in your daily work, making you a more productive developer. In Gulp you write all tasks in… wait for it… javascript! Being written in code it gives you more flexibility than configuration done with javascript objects. It uses Node.js streams which simplified means you:

  1. have an input (some files, maybe javascript or css)
  2. which you perform an action on
  3. and finally send to some output

Think of it as a pipeline where at certain points along the pipe actions are performed, e.g. linting, concatenating, transforming, minifying, testing etc.

To concretize even more, let’s look at the simple api that Gulp exposes:

  • gulp.task: the task/action to perform
  • gulp.src: the input, which files
  • gulp.dest: the output
  • gulp.watch: detect changes and run tasks automatically

Could it be more easy? 🙂

Simple workflow in Gulp

Let’s walk through the code that is necessary for setting up a nice, easy workflow that you can use as a starting point in your javascript projects. The plan is to have one ”build” task that does linting, concatenating and minifying of our javascript files, one ”test” task that will run our tests and finally one ”watch” task that will detect file changes and automatically reload the browser.

Install

I assume you are familiar with Node.js and has its package manager npm installed. Let’s create a node project and a package.json:

npm init

Install Gulp:

npm install gulp -g

Install the Gulp plugins needed for our workflow:

npm install gulp-jshint gulp-mocha gulp-concat gulp-uglify gulp-livereload --save-dev

Create gulpfile.js (our Gulp.js configuration file) and require the plugins:

var gulp = require('gulp'),
    jshint = require('gulp-jshint'),
    mocha = require('gulp-mocha'),
    concat = require('gulp-concat'),
    uglify = require('gulp-uglify'),
    livereload = require('gulp-livereload');

Linting with gulp-jshint

JSHint is ”a tool that helps to detect errors and potential problems in your JavaScript code”. Let’s use it as first step in the build task, add the following code to gulpfile.js:

gulp.task('build', function() { 
    return gulp.src('src/scripts/**/*.js')
    .pipe(jshint()) 
    .pipe(jshint.reporter('default'));
});

What happened here? A task called ”build” was defined and a function that is the content of the task was provided. The function Gulp src api is used to select the input (our javascript files) before using pipe to stream to the next step which is using JSHint to analyze our code and finally handing over to the next step in the pipe that is reporting the result. The following task can be run from command line:

gulp build

Concatenation with gulp-concat

This plugin will concatenate multiple javascript files into one bundled file, which then is the only file needed to be referenced from our HTML page. Lets add it to our existing task:

gulp.task('build', function() { 
    return gulp.src('src/scripts/**/*.js')
    .pipe(jshint()) 
    .pipe(jshint.reporter('default'))
    .pipe(concat('bundle.min.js'))
    .pipe(gulp.dest('public/js'));
});

As you can see we just add this to the chain of pipes, meaning it will take the output of the previous action and continue to work with it, combining the multiple source files into one new file called bundle.min.js. It will place it in a public/js folder using Gulp dest api.

Minifying with gulp-uglify

This plugin will take the javascript file(s) and ”parse, compress and beautify”. We want to make our final single javascript file as small as possible to reduce load time. Let’s add it:

gulp.task('build', function() { 
    return gulp.src('src/scripts/**/*.js')
    .pipe(jshint()) 
    .pipe(jshint.reporter('default'))
    .pipe(concat('bundle.min.js'))
    .pipe(gulp.dest('public/js'))
    .pipe(uglify())
    .pipe(gulp.dest('public/js'));
});

That concludes our build task and we now have a problem free (eeeh, hopefully), minified, single javascript file the can be referenced from our HTML page.

Testing with gulp-mocha

Mocha is ”a javaccript test framework running on Node.js, featuring browser support, asynchronous testing, test coverage reports, and use of any assertion library. It’s pretty awesome so let’s add a task for it:

gulp.task('test', function() { 
    return gulp .src('test/*.js')
    .pipe(mocha());
});

This will take all the test javascript files and hand it over to mocha who will run all tests.

Automatic reload with gulp-livereload

This plugin ”monitors changes in your file system (for example, your CSS, images or javascripts). As soon as a change is detected the browser is refreshed automatically”. (To make it work you need to install the plugin (here’s for Chrome) or include a script snippet.) Lets create the ”watch” task using gulp-livereload and Gulp api watch:

gulp.task('watch', function() {
    gulp.watch('src/scripts/**/*.js', ['build']);
    livereload.listen();
    gulp.watch(['public/**']).on('change', livereload.changed);
});

By using Gulp watch api we detect changes in our javascript files and run the ”build” task. Then livereload server i started and will listen to changes. Finally, when a new bundle.js is created and placed in public folder livereload will detect that change and reload the browser for us. This means that as soon as you save a javascript source file the changes will be reflected in the browser.

Default task to do it all

Finally, lets create a default task that will both build and start watching our source files:

gulp.task('default', ['watch', 'test', 'build']);

This ”default” task have three dependencies that it will run, which happens to be our newly created ”test”, ”watch” and ”build” tasks. So now all you need to do is run this from command line:

gulp

You can of course run these tasks individually:

gulp test
gulp build
gulp watch

Here’s the final code in gulpfile.js

var gulp = require('gulp'),
    jshint = require('gulp-jshint'),
    mocha = require('gulp-mocha'),
    concat = require('gulp-concat'),
    uglify = require('gulp-uglify'),
    livereload = require('gulp-livereload');

gulp.task('build', function() { 
    return gulp.src('src/scripts/**/*.js')
    .pipe(jshint()) 
    .pipe(jshint.reporter('default'))
    .pipe(concat('bundle.min.js'))
    .pipe(gulp.dest('public/js'))
    .pipe(uglify())
    .pipe(gulp.dest('public/js'));
});

gulp.task('test', function() { 
    return gulp .src('test/*.js')
    .pipe(mocha());
});

gulp.task('watch', function() {
    gulp.watch('src/scripts/**/*.js', ['build']);
    livereload.listen();
    gulp.watch(['public/**']).on('change', livereload.changed);
});

gulp.task('default', ['watch', 'test', 'build']);

Final thoughs

Aren’t there any downsides to this? Well, both Gulp and Grunt is very plugin and community driven… Otherwise I think it’s mostly upsides and it saves A LOT of time.

Annonser

2 reaktioner på ”Gulp – super simple workflow automator

Kommentera

Fyll i dina uppgifter nedan eller klicka på en ikon för att logga in:

WordPress.com Logo

Du kommenterar med ditt WordPress.com-konto. Logga ut / Ändra )

Twitter-bild

Du kommenterar med ditt Twitter-konto. Logga ut / Ändra )

Facebook-foto

Du kommenterar med ditt Facebook-konto. Logga ut / Ändra )

Google+ photo

Du kommenterar med ditt Google+-konto. Logga ut / Ändra )

Ansluter till %s