Getting Started with Gulp

gulp.js is a fantastic way of removing some of the more mundane parts of a web designer or developer’s job. It takes away all the tasks you should be doing and probably some of the ones that you’re not but should be!

For example tasks like:

  • compiling your CSS, LESS or SASS down to minified versions with vendor specific prefixes
  • minifying, obfuscating and even uglifying your CoffeeScript or JavaScript files down to production versions
  • push to your browser, so you can see the changes without reloading the page
  • automatically run PHPUnit (for example) against any code changes
  • and watch for anything above changing and do it all again!

To read the full article with code examples, please head over to my guest post at webdevtuts.co.uk. This article was originally written for the above publication which, sadly, no longer exists, so I've republished it to my blog.

gulp.js is a JavaScript based command line task runner built using Node.js.

Now if you are using something like Grunt the above will make absolute sense. However, if this is your first time thinking about using command line JavaScript tools the whole idea can seem a bit alien. Just follow along and if you've got any questions then please add them in the comments.

First things first, you'll need Node.js installed, which is beyond the scope of this introduction but is particularly easy, especially if you're on a Mac like myself. Visit nodejs.org, click 'Install', download the package and install it just like anything else.

Next fire up the command line, which might be Terminal or in my case iTerm2 and type 'npm'. You should see Node's Package Manager information screen. Right now you've got Node.js sorted let's move onto the good stuff.

Create a test folder somewhere on your machine. In my case I'm going to create 'gulptest' on my desktop. Back in Terminal change to this new directory cd /Users/Chris/Desktop/gulptest/.

Let's install gulp globally on your machine npm install -g gulp Depending on your setup and any errors you see you may need to run this as root sudo npm install -g gulp

Type gulp and you should find Terminal barks back the error [gulp] No gulpfile found. That's okay we're going to create that in a minute, it just means everything is installed and working. Now we're going to install a bunch of plugins that is going to make gulp.js really useful. A list of all the available gulp.js plugins is available on their website.

For this little project I'm going to assume you use LESS, some JavaScript and you'd really like to see your browser reloading without having to refreshing.

npm install --save-dev gulp gulp-util
npm install --save-dev gulp-less gulp-autoprefixer gulp-minify-css gulp-concat gulp-uglify gulp-rename gulp-livereload gulp-notify tiny-lr`

I've separated out the above into two lines purely so it's a little easier to understand. Using the —save-dev command writes the required plugins into our gulpfile.js meaning we can easily move this file to another project or hand it over to someone else to use. You could easily use this instead:

npm install --save-dev gulp gulp-util gulp-less gulp-autoprefixer gulp-minify-css gulp-concat gulp-uglify gulp-rename gulp-livereload gulp-notify tiny-lr

Again any trouble installing any of those on your setup, then try with sudo in front of the commands.

Time to create that gulpfile.js file Terminal asked for earlier. This is the configuration file which we'll use to tell gulp what to do with our files.

Add references to the plugins we installed at the top of the file:

// Include main components
var gulp = require('gulp');
var gutil = require('gulp-util');
var lr = require('tiny-lr');

// Include CSS components
var less = require('gulp-less');
var prefixer = require('gulp-autoprefixer');
var minifycss = require('gulp-minify-css');

// Include JS components
var concat = require('gulp-concat');
var uglify = require('gulp-uglify');

// Include utilities
var rename = require("gulp-rename");
var livereload = require('gulp-livereload');
var server = lr();

I also like to use a couple of variables to manage locations within my gulp file, it makes life easier long term.

// Source and Target directories
var sourceLESS = 'source/less';
var targetCSS = 'public/css';

var sourceJS = 'source/js';
var targetJS = 'public/js';

Go ahead and create those folders too within your main gulptest folder.

Let's go ahead and create our first task with gulp to process any LESS files we have, add vendor-specific prefixes, minify, rename, save to our public CSS folder and finally push the changes to our browser. To take advantage of the live reload functionality we need to install the LiveReload Chrome extension.

// LESS compilation
gulp.task('less', function () {
	gulp.src(sourceLESS + '/app.less')
		.pipe(less().on('error', gutil.log))
		.pipe(prefixer('last 10 versions'))
		.pipe(minifycss())
		.pipe(rename("app.min.css"))
		.pipe(gulp.dest(targetCSS))
		.pipe(livereload(server));
});

gulp allows us a beautiful way of just piping each command we want to run in succession so the above reads as follows:

create a gulp task called 'less'
	use this source file 'source/less/app.less' to
		compile the LESS files (and log the error if there is one rather than fail)
		add vendor specific prefixes for the last 10 versions of major browser
		minify the compiled CSS
		rename the file to 'app.min.css'
		save it to the 'public/css' folder
		and finally, push the changes to the browser

We'd better create a really basic LESS file within source/less/ called app.less. In that let's just put something simple as we aren't actually going to view the results in the browser, just purely in the public/css folder to see the changes.

body {
	padding: 20px 0;
	
	p {
		margin-bottom: 8px;
	}
}

Ok, with all that in place, let's take it for a trial run with gulp less in Terminal which should produce similar results to this:

[gulp] Using gulpfile /Users/Chris/Desktop/gulptest/gulpfile.js
[gulp] Starting 'less'...
[gulp] Finished 'less' after 11 ms

And take a look inside public/css? Can you see app.min.css? Fingers crossed you can, it's the start of something special but not massively useful right now.

Let's create a couple more tasks for JavaScript and live reloading:

// JS compilation
gulp.task('js', function() {
	gulp.src(sourceJS + '/app.js')
		.pipe(concat("app.min.js"))
		.pipe(uglify({mangle: true}).on('error', gutil.log))
		.pipe(gulp.dest(targetJS))
		.pipe(livereload(server));
});

// LiveReload
gulp.task('livereload', function(next) {
	server.listen(35729, function(err) {
		if (err) return console.error(err);
		next();
	});
});

Before we test the JS compilation create a quick test file within source/js called app.js containing the following:

$(function() {
	var testVar = 'I am a test variable';
	
	alert(testVar);
})

Ok, fire up the Terminal again and try gulp js. You should see a minified app.min.js within public/js.

Right so this all well and good but we don't want to type gulp less or gulp js every time we make a change. That's no help at all. You're not wrong, let's create a watcher to look for changes as they happen:

// Watch for LESS and JS changes and run the respective compilers automatically
gulp.task('watch', function () {
    gulp.watch(sourceLESS + '/app.less', ['less']);
    gulp.watch(sourceJS + '/app.js', ['js']);
});

Now we should be able to type gulp watch and gulp will sit there and check for any changes and run the correct compiler as and when we make change. Give it a try change the padding in app.css or the contents of testVar in app.js. (If you're not a regular to command line routines, you need to press Ctrl + C to quit the gulp watch task.)

Lastly wouldn't it be great if you could just type gulp and everything happened? Right now you'd get the following error:

[gulp] Using gulpfile /Users/Chris/Desktop/gulptest/gulpfile.js
[gulp] Task 'default' was not defined in your gulpfile but you tried to run it.

Before we finish up, we'll create that default task:

// Default Task
gulp.task('default', ['livereload', 'less', 'js', 'watch']);

This will setup the livereload server, run the LESS task, JS task and finally the watch task which will continue looking for file changes.

That's pretty much it. We've not got task runner constantly looking for LESS or JS changes and compiling them down to single minified files and all we need to run is gulp. I don't know how you were doing it before but I guarantee once you've got set this up it's a lot cleaner and simpler to do on a per project basis.

I haven't particularly touched upon the live reload task within this gulefile.js. I was quite amazed that with the above code, the Chrome extension and running gulp that this just worked!