— Gulp, JavaScript — 5 min read
![GulpJS](/content/images/2015/Mar/gulp_white_text.svg)
I recently started working with GulpJS as part of my build process and I have to say I am extremely impressed. I thought I would do a quick write up of how I used Gulp while working on a recent jQuery plugin and fell in love with the process.
If you are a Front-end Developer who has been living under a hole for the last few months, you might not have heard of Gulp yet. It is a javascript task runner, similar to GruntJS but is, to me anyway, a lot more intuitive. Why? It seems more like writing real javascript. It uses Node streams to send your code through the asset pipeline and can pretty much do anything that Grunt can do with less configuration. If you are interested in a more in depth look at what Gulp is, I highly recommend reading the documentation.
When you start up with Gulp, you obviously need to have Node installed. I won't go into how to install node here (just follow the documentation on the node website). If you haven't already installed Gulp just run the following code from the command line:
1npm install -g gulp
That's all you need to get things started. Of course, like Grunt, there are a ton of plugins available to help you do things. So I wrote out a list of the tasks I wanted Gulp to do for me:
After searching through the Gulp plugins I found plugins that matched each of my needs and I installed them. The end.... but I'm guessing you probably want a little more detail than that. So let's go through it one step at a time and build up our base Gulpfile (the main javascript file that defines and executes our tasks).
Watching files for changes and copying them to new locations are functions that are built-in to Gulp so no plugins are needed. Let's just get that out of the way and start with a super simple Gulpfile.
1var gulp = require( 'gulp' );2gulp.task( 'javascript', function() {3 gulp.src( './src/**/*.js' ).pipe( gulp.dest( './dist/' ) );4)};56gulp.task( 'watch', function() {7 gulp.watch( './src/**/*.js', ['javascript'] );8});910// The default task (called when you run `gulp` from cli)11gulp.task( 'default', ['watch']);
The first thing we do is include gulp in our file. Next, we define a task called javascript
. This will contain everything that we want gulp to do when this task is run. Currently, we are just copying our existing JavaScript files to our dist
folder. Then, we define a task called watch
. It uses gulps built in monitoring to watch the folder and files specified for any changes and then runs the array of tasks provided. In this case, we are watching all the javascript files in our js folder (and all it's subfolders). We are only provide one task: our javascript
task.
We can run this a couple of ways. To manually run the javascript
task, just type gulp javascript
on the command line from our main folder. We can run gulp watch
to have gulp monitor our files for changes, and automatically run our javascript
task. That's better... but we set our watch
task to be the default one. So all we really have to do is run gulp
from the command line and it will automatically run the watch
task. Cool!
Two of our requirements are now complete.
So let's get minification handled. I found the gulp-uglify plugin and installed it. Since I knew I would be using these in projects going forward I will install the plugins globally (using -g
). If you do not want to do that just remove that flag from the examples and you will be good to go.
1npm install gulp-uglify
Now let's update our Gulpfile.js.
1var gulp = require( 'gulp' );2var uglify = require( 'gulp-uglify' );34gulp.task( 'javascript', function() {5 return gulp.src( './src/**/*.js' ) // folder(s) this task will run against6 .pipe( uglify() ) // minify the code7 .pipe( gulp.dest( './dist/' ) ); // copy original to destination folder8 )};910gulp.task( 'watch', function() {11 gulp.watch( './src/**/*.js', ['javascript'] );12});1314// The default task (called when you run `gulp` from cli)15gulp.task( 'default', ['watch']);
Now before we copy our files over, we run each file through the minification process first. But wait that's not quite what we want... Yes, we want our javascript file copied to our dist
folder but we want it to be have .min.js as well. Guess what? There is a plugin for that. It is called gulp-rename. So let's install that plugin as well.
1npm install gulp-rename
Cool! Now let's modify our Gulpfile just a little bit.
1var gulp = require( 'gulp' );2var uglify = require( 'gulp-uglify' );3var rename = require( 'rename' );45gulp.task('javascript', function() {6 return gulp.src( './src/**/*.js' )7 .pipe( gulp.dest( './dist/' ) ) // copy original to destination folder8 .pipe( uglify() ) // minify the code9 .pipe( rename( { suffix: '.min' } ) //rename to .min10 .gulp.dest( './dist/' ) ); // copy renamed file to destination folder11 )};1213gulp.task( 'watch', function() {14 gulp.watch( './src/**/*.js', ['javascript'] );15});1617// The default task (called when you run `gulp` from cli)18gulp.task( 'default', ['watch']);
Easy right? Now we have a copy of both the minified and un-minified file in our dist
folder. We have successfully completed another of our requirements. Let's mark it off of our list and move on to the next item.
I think linting should be next on our list. There are two plugins I want to install for linting. The main one is jshint. This is our linting library and is all that is required to install. But, I also want to install jshint-stylish. This makes the output from jshint look a little, well, more stylish. First, let's install them both. Notice a slightly different syntax for jshint-stylish. This isn't a gulp plugin per se but instead a node package that works with our jshint library.
1npm install gulp-jshint jshint-stylish --save-dev
And add them to our Gulpfile
1var gulp = require( 'gulp' );2var uglify = require( 'gulp-uglify' );3var rename = require( 'rename' );4var jshint = require( 'jshint' );56gulp.task('javascript', function() {7 return gulp.src( './src/**/*.js' )8 .pipe( jshint() ) // lint out file9 .pipe( jshint.reporter( 'jshint-stylish' ) ) // output to stylish10 .pipe( gulp.dest( './dist/' ) ) // copy original to destination folder11 .pipe( uglify() ) // minify the code12 .pipe( rename( { suffix: '.min' } ) //rename to .min13 .pipe( gulp.dest( './dist/' ) ); // copy renamed file to destination folder14 )};1516gulp.task( 'watch', function() {17 gulp.watch( './src/**/*.js', ['javascript'] );18});1920// The default task (called when you run `gulp` from cli)21gulp.task( 'default', ['watch']);
Woohoo! Now we are linting our code. And, for the paranoid out there, you can always re-lint your code after the minification process as well. I'm not doing it here for the sake of simplicity but it is something to consider. So we can mark off another one of our items off the list.
Well before we ship this off, we should probably make sure our javascript is passing their tests correctly. In this case, I used qunit. I chose this because I was working on a jQuery plugin. Since the jQuery team uses it to test their plugins et al, I did the same. Feel free to use whatever testing library you prefer. I am sure there is a gulp plugin for you.
I am going to skip the installation steps going forward ( npm install blah blah blah
). I'm pretty sure you have got the idea by now. Let's update our Gulpfile again :-)
1var gulp = require( 'gulp' );2var uglify = require( 'gulp-uglify' );3var rename = require( 'rename' );4var jshint = require( 'jshint' );5var qunit = require( 'gulp-qunit ');67gulp.task('javascript', function() {8 return gulp.src( './src/**/*.js' )9 .pipe( jshint() ) // lint out file10 .pipe( jshint.reporter( 'jshint-stylish' ) ) // output to stylish11 .pipe( qunit() ) // run tests12 .pipe( gulp.dest( './dist/' ) ) // copy original to destination folder13 .pipe( uglify() ) // minify the code14 .pipe( rename( { suffix: '.min' } ) // rename to .min15 .pipe( gulp.dest( './dist/' ) ); // copy renamed file to destination folder16 )};1718gulp.task( 'watch', function() {19 gulp.watch( './src/**/*.js', ['javascript'] );20});2122// The default task (called when you run `gulp` from cli)23gulp.task( 'default', ['watch']);
Easy peasy. Another one down.
Now, if you wanted I think you could just stop right there and have a really nice build system in place. But there are a few more things that I think can be useful. In some applications, you have multiple javascript files. In those cases, you should probably combine those into a single file for use in a production environment. If that is the case, you can use gulp-concat. Also, you might want to add a revision onto your file so that you can break the users' cache and force them to receive the updated file. For that you can use gulp-revision. Since they were some of my requirements listed above , let's include them. Lastly, I pulled out a lot of my strings and set them up as variables to make the code a little more DRY and easier to modify later on.
1var gulp = require( 'gulp' ),2 uglify = require( 'gulp-uglify' ),3 rename = require( 'rename' ),4 jshint = require( 'jshint' ),5 qunit = require( 'gulp-qunit' ),6 rev = require( 'gulp-rev' ),7 concat = require( 'gulp-concat' ),8 source = './src/**/*.js',9 destination = './dist/',10 filename = 'all.js',11 renameOptions = { suffix : '.min' };121314gulp.task('javascript', function() {15 return gulp.src( source )16 .pipe( concat( filename ) ) // combine our files17 .pipe( jshint() ) // lint out file18 .pipe( jshint.reporter( 'jshint-stylish' ) ) // output to stylish19 .pipe( qunit() ) // run tests20 .pipe( gulp.dest( destination ) ) // copy original to destination folder21 .pipe( uglify() ) // minify the code22 .pipe( rename( renameOptions ) // rename to .min23 .pipe( rev() ) // add revision to minified file24 .pipe( gulp.dest( destination ) ); // copy renamed file to destination folder25 )};2627gulp.task( 'watch', function() {28 gulp.watch( source , ['javascript'] );29});3031// The default task (called when you run `gulp` from cli)32gulp.task( 'default', ['watch']);
Now, we combine all of our javascript into one file called all.js
and after we create a minified version of the file we add a revision suffix to the file before we move it to our dist
folder. We can now mark our last two items off the list.
We have met all our requirements but I did run across a few other plugins that I thought would be useful. I don't think I need to explain how to add them into your gulpfile at this point.
There are plenty more quality plugins out there. These are just a couple that I ended up using in my javascript
task.
dist
folder before you rebuild your files.I really like using Gulp over Grunt. I find the code easier to read, understand and modify. In a future post I will be adding additional tasks. The next one up: [Using Gulp with CSS]((/intro-to-gulp-part-2)CSS! Happy Gulping!
'Til next time!
-G