The A List Apart Blog Presents:

Getting Started with Gulp

Article Continues Below

While building JavaScript related projects (whether server side via Node.js or front-end libraries), a build tool to help easily maintain and automate many of the processes—including testing, concatenating files, minification, compiling templates, as well as many other options—can be incredibly useful. This takes the step out that’s most prone to error (me, in the case of my projects) and replaces it with a fast and consistent system that never forgets to update or copy your files over. There are many great build tools, including Grunt, Broccoli, and Brunch.

One of these build tools that I find particularly helpful is gulp.js. It’s fast and I’ve found it really easy to work with since I learned how to set it up and incorporate it into a workflow. Today, I’m going to walk through that process.

So, what’s gulp? Gulp is build system built on the concept of streams. Bear with me here, I might need to go a little high level on this. Streams are a way to develop large pieces of software out of many small pieces. The philosophy behind it is for each component to do one thing and to have the same way of communicating as the next. This allows you to mix and match these small components so you can take the output from any one that follows this philosophy and plug it into the next. The principles of streaming are significant in Node.js and as a platform, Node gives some helpful syntax for the utilization of streaming. Gulp, as a Node.js tool, utilizes this syntax and follows these principles to allow the user to piece together a large build system while escaping a lot of the complexity that comes with big tools that do a lot of things. A quick example of this is in the way gulp tasks are structured, using the pipe method.

gulp.src('script/lib/*.js') // read all of the files that are in script/lib with a .js extension
  .pipe(jshint()) // run their contents through jshint
  .pipe(jshint.reporter('default')) // report any findings from jshint
  .pipe(concat('all.js'))

One stream is piped into a destination, which is then piped into another destination, and so on and so forth. We’ll come back to this example later.

Now, I know what you’re thinking, “This sounds like a lot to learn in order to do some basic stuff that I can just do by hand,” and if you are thinking that:

  • I’m a mindreader and this is totally going to work out for me; and
  • We should talk about the benefits of an automated build system.

If you’re already using something to perform the concatenation, minification, testing, etc. of your files—go ahead and skip to the next paragraph. I’ll take care of you there. If not, let’s get right to the point in business terms: the initial cost incurred in you learning to use this technology and spin it up on your projects will be made up for exponentially with a decrease in risk for both errors and required knowledge to be transferred if somebody else comes onto the project.

Maybe you’re not thinking that, maybe you’re thinking, “I already use Grunt for all my processes. I’m the Admiral of Automation, the Captain of the Command line, the General of…um…you get where I am going with this. I am very good at setting up my own projects with my build tool of choice.” That’s awesome! Though, in my experience, it never hurts to learn something new, and who knows? You might even like this better!

What’s better about gulp? First, it’s fast. Since gulp uses that stream thing I mentioned earlier, it’s very nature is in passing data from one program to another instead of reading a file, performing a task, writing a file, then doing that again with another task. Another thing that’s nice about gulp is how easy it is to read. Since it’s just short bits of code, it becomes very clear, very quickly, what your tasks do. This differs from other systems that use a configuration file in that configuration files tend to mean jumping around in a file a lot and making sure you’re keeping track in your head what’s going on and where it’s happening. This may not seem like a big deal if you’re the person who set up the configuration or if you’re early in the project, but if you’re new and debugging—the more you have to keep track of, the worse.

This is what had me, faster and easier to understand? Sold.

Now that you’ve heard a little bit of the why, let’s talk about the how. Installation is dead simple, thanks to our good friend, NPM.

First, make sure gulp is installed globally.

npm install -g gulp

Now, in your project, install gulp as a developer dependency

npm install --save-dev gulp

Next, make gulpfile.js in the root of your project

var gulp = require('gulp');

gulp.task('default', function() {
  // place code here
});

Lastly, run gulp from your command line

gulp

[20:27:35] Using gulpfile ~/code/example/gulpfile.js
[20:27:35] Starting 'default'...
[20:27:35] Finished 'default' after 45 μs

Nice.

Let’s get to writing a task. Now, on any normal project, I’m likely going to want to run JShint on my files, concatenate all of them, and then minify. I’ll also want to make sure a minified and non-minified version are saved. First, let’s make sure to install the plugins via NPM as well. We can do that by placing these in our package.json.

'gulp-jshint': '1.9.0',
'gulp-concat': '2.4.2',
'gulp-rename': '1.2.0',
'gulp-uglify': '1.0.2'

And running npm install

Now, let’s write that gulpfile:

var gulp = require('gulp');
var jshint = require('gulp-jshint');
var concat = require('gulp-concat');
var rename = require('gulp-rename');
var uglify = require('gulp-uglify');

gulp.task('js-linting-compiling', function(){
  return gulp.src('script/lib/*.js') // read all of the files that are in script/lib with a .js extension
    .pipe(jshint()) // run their contents through jshint
    .pipe(jshint.reporter('default')) // report any findings from jshint
    .pipe(concat('all.js')) // concatenate all of the file contents into a file titled 'all.js'
    .pipe(gulp.dest('dist/js')) // write that file to the dist/js directory
    .pipe(rename('all.min.js')) // now rename the file in memory to 'all.min.js'
    .pipe(uglify()) // run uglify (for minification) on 'all.min.js'
    .pipe(gulp.dest('dist/js')); // write all.min.js to the dist/js file
});

I’ve added some comments next to each line, but let’s take a closer look:

var gulp = require('gulp');
var jshint = require('gulp-jshint');
var concat = require('gulp-concat');
var rename = require('gulp-rename');
var uglify = require('gulp-uglify');

At the top, I’m requiring each plugin that I’ll be using as well as gulp itself.

gulp.task('js-linting-compiling', function(){

Now I’m creating a task and naming it “js-linting-compiling,” because I am not very creative and that is pretty descriptive.

return gulp.src('script/lib/*.js')

Now I’m reading the files that are in the script/lib folder that have the extension .js. This line begins with a return, because I’m returning a stream from the task itself.

From this point forward, think about streams. The component takes in input, makes a change, and then produces output that the next component can read.

    .pipe(jshint()) // run their contents through jshint
    .pipe(jshint.reporter('default')) // report any findings from jshint
    .pipe(concat('all.js')) // concatenate all of the file contents into a file titled 'all.js'
    .pipe(gulp.dest('dist/js')) // write that file to the dist/js directory
    .pipe(rename('all.min.js')) // now rename the file in memory to 'all.min.js'
    .pipe(uglify()) // run uglify (for minification) on 'all.min.js'
    .pipe(gulp.dest('dist/js')); // write all.min.js to the dist/js file

That will hopefully get you started. If you’d like to learn more, check out:

11 Reader Comments

  1. Thanks for the nice quick and clear synopsis! I like task runners but, after dealing in some real world large scale web applications, I’ve been turned off to systems like Grunt because of the config file maintenance headache. I really like Gulp’s approach: much cleaner, clearer, and easier to maintain.

  2. Great introduction! Thanks. Once you’ve had a Gruntfile get out of hand, the appeal of gulp becomes apparent.

    I think you have a small typo.

    `npm install—save-dev gulp` should be

    npm install gulp --save-dev

    with a space and two dashes. Perhaps the CMS ate them.

    If you’re interested in working with gulp, you’ve probably already used Grunt, and probably know what a `package.json` file is.

    But if you don’t, once you install NodeJS – toodle over to your Terminal, cd into a new project directory and use `npm init` to generate a new package.json file with sensible defaults.

  3. Great post! I switched to Gulp several projects ago and haven’t looked back. While I love what Grunt does and appreciate its plugin community, the configuration files just didn’t gel with my brain.

    I’d also recommend checking out gulp-starter, a really helpful example of how to avoid overloading gulpfile.js for large projects. I don’t follow all of its suggestions, but its use of separate files for tasks is pretty clever and demonstrates Gulp’s flexibility really well. (Hat-tip to Lyza Gardner’s Gulp post for that resource.)

  4. Like other commenters, I found Gulp a refreshing change after starting with the complexity that is Grunt.

    Thanks for the clear rundown of how to get started with Gulp. I hope this will encourage others to pick up this tool for their next project!

  5. Interesting, is there any reason why you’re creating all.js, saving it and then renaming it?

    For JS I lint files, concatenate them, uglify and save to destination folder without any intermediary step for unminfied version as that’s not really needed (nor desirable) for production. (I also use ‘del’ to wipe destination folder before writing new files to it)

    Another (mostly for CSS) important tool is gulp-order which allows you to set files in specific order and then concatenate the rest after them (for example you might have base.css, grid.css and then the rest).

    One really nice feature of Gulp in comparison with Grunt is that ‘watch’ is built-in and you don’t need to have another dependency. ‘gulp-notify’ is quite handy for those who like notifications (I do, I’m also using ‘gulp-notify’ for custom notifications for JSHint in addition to console output).

Got something to say?

We have turned off comments, but you can see what folks had to say before we did so.

More from ALA

Nothing Fails Like Success

Our own @zeldman paints the complicated catch-22 that our free, democratized web has with our money-making capitalist roots. As creators, how do we untangle this web? #LetsFixThis