Gulp Build System Part 1: Fundamentals
If in the past you have ever been intimidated or confused trying to set up a front-end build system you are not alone. A few years ago I had my first introduction to the process watching a video series on YouTube about Grunt. At the time I diligently followed the videos and within a few hours had my first working Grunt setup, well sort of. It functioned as advertised, but to be honest I had no real understanding of how all the Grunt syntax worked, or how all the parts fit together.
If like me you have been scratching your head trying to make sense of it all then keep reading. This post will help give you an overview and provide a scaffolding to help demystify some of these moving parts as well as looking at a simpler, faster replacement for Grunt.
What is a Build System
1. Package Managers
Package managers are tools that are used to automate the installation, upgrading, removal, and dependencies for the packages and libraries used in your dev environment. We will be using both Bower and NPM (Node Package Manager) in our upcoming workflow. If it seems redundant to use two package managers instead of just picking one or the other I completely appreciate where you are coming from. It took me quite a bit of research before I started to understand the subtle distinction between the two. While both manage dependencies, their intended target environments are different.
As you can see in the diagram above, Bower manages our front-end dependencies while NPM is used to manage dependencies within the Node.js environment. If this still seems a little confusing then look at it like this: Bower is used to manage libraries like jQuery, Backbone, or RequireJS that affect your actual project files. NPM on the other hand handles utility modules that work with node to assist in your build process.
This explanation is of course a gross oversimplification. Both Bower and NPM have many overlapping responsibilities and in some cases the line might be blurred. Though their might be some grey areas to deal with, in general, understanding the intent of both package managers will help clarify which dependencies go where.
- CSS: Sass, Less, Stylus
- HTML: HAML, Jade, Markdown, Slim
While most preprocessors can be used independent of build tools like Gulp or Grunt, pairing your preprocessors with your build tools gains you both efficiency and enhanced functionality. For example, watch tasks are frequently created to watch for file changes and then update the browser. We will look at this much more in detail in part three of this series.
3. Task Based Build Tools
Now lets get to the meat of it, Gulp and Grunt. Both run on Node, both are great tools, and both share a similar anatomy. Although we will be using Gulp in this series, Grunt follows the same overall structure. We will be getting into a few of the core differences between Grunt and Gulp in the next section, but for now lets take a look at the structure of a typical gulp file.
Starting at the top and moving down, the first step is to declare which modules will be required by Gulp. This is where we declare both gulp itself as well as all the dependencies we need for our build.
var gulp = require( 'gulp' );
var uglify = require( 'gulp-uglify' );
Following this we have our named tasks (name them whatever makes sense to you) which tell Gulp what you would like it to actually do. One optional task that is also frequently added is the ‘watch’ task. When you add this special task you specify certain files and folders that you want Gulp to watch. When Gulp detects a change, it will automatically run one of your named tasks.
// named task 'scripts'
// watch folder 'js' for all files ending in .js. On change runs 'scripts' task
gulp.watch( 'app/js/**/*.js', ['scripts'] );
Named tasks can be run by simply running “gulp [task-name]” into your terminal. Named tasks can do anything from compressing static images and copying files to creating a deployment build. To run a task named ‘scripts’ you would type:
There is one additional task that is usually used as well. It is called the ‘default’ task and it simplifies the process even more by running a series of tasks define in an array by simply using the command ‘gulp’. It’s important to note that these task are called asynchronously and all fire up at the same time. This default behavior can be overridden if you require a particular sequence of tasks to run. I will demonstrate how this can be accomplished when we start coding up our actual build.
// default task runs both 'scripts' and 'watch' tasks
gulp.task( 'default', [‘scripts’, ‘watch’] );
Grunt Vs Gulp
So should you use Grunt or Gulp for your next project? It doesn’t really matter. Both do exactly the same thing, they just do it in different ways. However as you may have guessed I feel Gulp has a slight advantage over Grunt in several respects.
- Grunt relies on A LOT of configuration and a steeper learning curve. For me personally I find the JSON styled syntax overly verbose and hard to remember, especially when revisiting the code several months later.
- Grunt can be slower. When Grunt runs a set of tasks it has to write the results of each task to a temp file before going to the next. This repetitive process can theoretically slow things down on a more complicated build. Gulp on the other hand uses streams which are readable, writable data that can be modified or piped (think Unix pipes) from one function to another. Because it does not have to write its results to a temp folder, and is executed asynchronously, it is able to take advantage of maximum concurrency.
While Grunt is still the big kid on the block, there seems to be a growing shift in momentum towards Gulp. I am seeing more and more developers endorsing Gulp. Even Google has switched to Gulp in their “Web Starter Kit”.
For me it boils down to ease of use. Gulp is much easier to learn, remember and ultimately maintain.
Please join me in the next section as we move away from theory and get deep into the code. We will build a practical example of a working build system as well as learn a few new tricks along the way.