- Updated Jan 28th, 2014 to reflect the advancement of gulp
- Updated Apr 21st, 2014 to utilise updated `gulp-livereload`
- Updated Aug 11th, 2014 Using `del` instead of `gulp-clean`, updated `gulp-livereload`
- Updated May 20th, 2015 Update `gulp-ruby-sass` syntax
- Updated Nov 2nd, 2015 Update `del` syntax
- Updated Jan 12th, 2016 `gulp-minify-css` depreciated. Use `gulp-cssnano`
Step aside Grunt, there's a new task runner in town. Gulp is an intuitive, code-over-configuration, streaming build system. It's fast.
Why should I be interested? Good question. Gulp’s code-over-configuration makes it not only easy to write tasks for, but also much easier to read and maintain.
Gulp uses node.js streams, making it faster to build as it doesn’t need to write temporary files/folders to disk. If you want to learn more about streams—although not necessary—this article is a good read. Gulp allows you to input your source file(s), pipe them through a bunch of plugins and get an output at the end, rather than configuring each plugin with an input and output—like in Grunt. Let’s take a look at an example of what a basic Sass build could look like with both Grunt and gulp:
Grunt requires each plugin to be configured separately, specifying source and destination paths for each plugin. For example, we input one file to the Sass plugin, which then saves the output. We then need to configure Autoprefixer to input Sass’s output, which then outputs another file. Let’s take a look at the same configuration with gulp:
With gulp we only input one file. This gets modified by the Sass plugin, passed to the Autoprefixer plugin and modified, then we get one file out. This process speeds up the build process as we’re not reading and writing unnecessary files to end up with one.
So you’re interested, now what? Let’s install gulp and create a basic gulpfile with some core tasks to get started.
Before we delve into configuring tasks, we need to install gulp:
This installs gulp globally, giving access to gulp’s CLI. We then need to install it locally to the project.
cd into your project and run the following (make sure you have an existing
This installs gulp locally to the project and saves it to the
devDependencies in the
Installing gulp plugins
We are going to install some plugins to achieve the following tasks:
- Sass compile (gulp-ruby-sass)
- Autoprefixer (gulp-autoprefixer)
- Minify CSS (gulp-cssnano)
- JSHint (gulp-jshint)
- Concatenation (gulp-concat)
- Uglify (gulp-uglify)
- Compress images (gulp-imagemin)
- LiveReload (gulp-livereload)
- Caching of images so only changed images are compressed (gulp-cache)
- Notify of changes (gulp-notify)
- Clean files for a clean build (del)
To install these plugins, run the following command:
This will install all necessary plugins and save them to
package.json. A full list of gulp plugins can be found here.
Load in the plugins
Next, we need to create a
gulpfile.js and load in the plugins:
Phew! That seems a lot more work than Grunt, right? Gulp plugins are slightly different from Grunt plugins—they are designed to do one thing and one thing well. An example; Grunt’s
imagemin uses caching to avoid re-compressing images that are already compressed. With gulp, this would be done with a cache plugin, which can also be used to cache other things too. This adds an extra layer of flexibility to the build process. Pretty cool huh?
We can auto load all installed plugins like in Grunt, but for the purpose of this post we’ll stick to the manual method.
Compile Sass, Autoprefix and minify
Firstly, we will configure Sass compiling. We’re going to compile Sass as expanded, run it through Autoprefixer and save it to our destination. We’ll then create a minified
.min version, auto-refresh the page and notify that the task is complete:
A little explanation before moving on.
This is the
gulp.task API which is used to create tasks. The above can run from Terminal with
$ gulp styles.
This is the new
gulp-ruby-sass API where we define the source file(s) and pass in any options. For many other plugins, you would use the
gulp.src API which we use later in this post (
return gulp.src(...)). It also can be a glob pattern, such as
/**/*.scss to match multiple files. By returning the stream it makes it asynchronous, ensuring the task is fully complete before we get a notification to say it’s finished.
.pipe() to pipe the source file(s) into a plugin. Usually the options for a plugin are found on their respective GitHub page. I’ve linked them above for convenience. Pipes are chainable so you can add as many plugins as you need to the stream.
gulp.dest API is where we set the destination path. A task can have multiple destinations, one to output the expanded version and one to output the minifed version. This is demonstrated in the above
I’d recommend checking out the gulp API documentaiton to get a better understanding of these methods. It’s not as scary as it sounds!
Hopefully you’ll now have a good idea of how to create a task for gulp. Next, we’ll set up the scripts task to lint, concat and uglify:
Here we use the
gulp.src API to specify our input files. One thing to note is that we need to specify a reporter for JSHint. I’m using the default reporter, which should be fine for most people. More on this can be found on the JSHint website.
Next, we’ll set up image compression:
This will take any source images and run them through the
imagemin plugin. We can go a little further and utilise caching to save re-compressing already compressed images each time this task runs. All we need is the gulp-cache plugin—which we installed earlier. To set this up, we need to change this line:
Now only new or changed images will be compressed. Neat!
Before deploying, it’s a good idea to clean out the destination folders and rebuild the files—just in case any have been removed from the source and are left hanging out in the destination folder:
We don’t need to use a gulp plugin here as we can take advantage of Node modules directly within gulp. We use a return to ensure the task finishes before exiting.
The default task
We can create a default task, ran by using
$ gulp, to run all three tasks we have created:
Notice the additional array in
gulp.task. This is where we can define task dependencies. In this example, the clean task will run before the tasks in
gulp.start. Tasks in Gulp run concurrently together and have no order in which they’ll finish, so we need to make sure the
clean task is completed before running additional tasks.
Note: It’s advised against using
gulp.start in favour of executing tasks in the dependency arrary, but in this scenario to ensure
clean fully completes, it seems the best option.
To watch our files and perform the necessary task when they change, we firstly need to create a new task, then use the
gulp.watch API to begin watching files:
We specify the files we want to watch via the
gulp.watch API and define which task(s) to run via the dependency array. We can now run
$ gulp watch and any changes to
.js or image files will run their respective tasks.
Gulp can also take care of automatically refreshing the page on file change. We’ll need to modify our
watch task, configuring the LiveReload server.
To make this work, you’ll need to install and enable the LiveReload browser plugin. You can also place the snippet in manually.
Putting it all together
Here we have the full gulpfile, embedded from this gist:
I’ve also put together a Gruntfile that accomplishes the same tasks, so you have take a look for a comparison, in the same gist.
If you have any questions or issues, please leave a comment below or you can find me on Twitter.