Looking at Gulp, an alternative to Grunt
I’ve been using Grunt for a while now, it’s a great way of managing your JavaScript workflow, for both client side and server side applications. We introduced it into our workflow for managing the minifying of JavaScript and running of tests/linting code, and we’re looking to expand its use further. Grunt has great community support and a huge range of plugins.
So it was with some scepticism I looked at Gulp, a new JavaScript task runner. My initial question of course being, “Why not just use Grunt?”. Having spent some time with Gulp though, I unexpectedly found myself enjoying using it.
Imperative vs Declarative
In Grunt you configure what you want to happen, this generally takes the form of a JavaScript object with properties defining the configuration of the tasks within your workflow. This works well once you know what you’re doing, but I found there was a learning curve to get to where you knew what you’re doing with your GruntFiles. Large and complex configurations can also be time consuming to read - it’s not particularly self-documenting.
Gulp is different, you tell it what to do, it feels much more like programming than Grunt does. The main advantage I found was when you come to Gulp, you already pretty much know how to use it, because you can program JavaScript. The example GulpFile I built below for my node app (hence no concat or minification) hopefully shows how simple it can be.
var gulp = require('gulp');
var mocha = require('gulp-mocha');
var gutil = require('gulp-util');
var jshint = require('gulp-jshint');
var jscs = require('gulp-jscs');
var watch = require('gulp-watch');
var src = './src/**/*.js';
var tests = './test/tests/**/*.js';
gulp.task('test', function () {
gulp.src(tests, { read: false })
.pipe(mocha({ reporter: 'spec' }))
.on('error', gutil.log);
});
gulp.task('lint', function() {
gulp.src([src, tests])
.pipe(jshint())
.pipe(jshint.reporter('default'))
.pipe(jscs())
.on('error', gutil.log);
});
gulp.task('default', function(){
gulp.run('test');
gulp.run('lint');
});
gulp.task('watch', function() {
gulp.src([src, tests], { read: false })
.pipe(watch(function(events, cb) {
gulp.run('default', cb);
}));
});
Gulp takes files as streams and pipes them through plugins. If you understand how streams work, then it’s pretty easy to slot your tasks together, but if you’re not familiar with node streams then it might not make sense immediately, especially when you trying to setup gulp-watch.
But Grunt works why bother?
A lot of the discussion has been around whether Gulp needs to exist when we have Grunt. Thankfully there’s also been plenty of sensible people pointing out that though they’re both task runners, there are situations where each excels.
Gulp, by placing streams at it’s core, needs something to stream, so if you’re wanting to do tasks without files, I’m not sure how well it’d work. Grunt has a huge plugin base already, where-as Gulp is newer so has less (though I didn’t find something I wanted to use that wasn’t supported, even the very new JavaScript Coding Standards npm was supported). I think Gulp is ideally suited to node js applications, as developers will likely already have a good understanding of streams.
Should you switch projects to Gulp instead of Grunt? No, there’s really no point. But if you’re starting a new project and you’re familiar with streams, I’d definitely recommend giving it a go, especially for Node applications.
All in all I found Gulp was a very pleasant development experience, and will definitely been keeping it mind when selecting a task runner for new projects, especially NodeJS.