Gulping the Kool-Aid

Conversations of front-end workflows have become an ever-so-popular topic amongst developers over the last few years. As developers, we’re constantly trying to shave seconds off our day-to-day and automate where necessary. We’ve come a long way from the early days of the web, and so have the tools — so why aren’t we embracing them?

As of the past year, I’ve become a huge evangelist of simplifying and offsetting the grunt work so I can spend valuable work hours doing the things I love, rather than the things I hate.

Gulp has single-handedly removed the mundane ever since I started injecting it into my workflow. Scaffolding new projects has never been easier, and all it takes nowadays to generate a project build is one command.

gulp

What, were you expecting more?

Now, I’d be lying if I didn’t mention that some amount of leg-work is required to get to this stage, but once your automating with Gulp, there really is no reason to ever go back to the hoop-jumping of yesteryear.

What the Gulp?

Gulp describes itself as a streaming build system, but I find it easier to describe it as a bonafide task runner; feed it a series of tasks, and watch it automate them. We define these tasks inside a file called gulpfile.js and Gulp kindly handles the rest for us.

Such tasks might involve minifying a stylesheet, or automatically adding vendor prefixes to properties that require them. What if we were watching that CSS file for changes, and what if we ran this task on every save? Wouldn’t it be even more helpful if we told Gulp to reload the browser on a save, so style changes were reflected in our browser immediately?

Now imagine how much time we could save if we wrote a few more tasks of that ilk.

Introducing Gulp Zero

Gulp Zero was born out of the need of a better starting point for my projects. I like to describe Gulp Zero as a low-calorie Gulp recipe, but it’s really just a lightweight stack of very useful Gulp plugins that serve as a great scaffolding tool for any project or application. You can find it here on GitHub.

Zero ships with my default stack of plugins. If a project calls for additional libraries, I add them on where necessary. I won’t bother going through the ones that are included, but if you’re the curious type, take a look at the package.json file.

Spin That Server

The first task is a fairly simple one to understand. We’re using BrowserSync’s built-in server to spin up a local server and serve files from the ./Build directory.

gulp.task('serve', function () {
  browserSync({
    server: './Build'
  });
});

What BrowserSync also provides is in its name. It keeps your project’s interactions, clicks and even scroll positions in sync across devices, simultaneously. Pretty handy for when you’re knee-deep in browser testing.

HTML files

Our HTML task is also pretty simple. We take our .html source files and save them to that ./Build directory I mentioned previously. 1

gulp.task('html', function() {
  return gulp.src('./src/*.html')
  .pipe(gulp.dest('./Build'))
  .pipe(reload({stream: true}));
});

Pay attention to that last line. We’re using Browsersync’s .reload() function to inform and refresh the browser at the end of certain tasks. More on this a bit later.

Beyond CSS

While this task may look overwhelming compared to the first two, we’re really just defining some source directories, just as we did previously, and piping them through a plugin called gulp-postcss with the help of another plugin, postcss-cssnext.

gulp.task('css', function () {
  return gulp.src(['./src/css/*.css', './src/css/**/*.css'])
  .pipe(postcss([cssnext]))
  .pipe(gulp.dest('./Build/css'))
  .pipe(reload({stream: true}));
});

It’s worth talking about where these plugins fit into our task. PostCSS transforms our CSS using PostCSS-cssnext, a tool that enables us to use the latest CSS syntax today. It does this by transpiling our futuristic (but notably incompatible) CSS into compatible CSS that works with the browsers we currently use.

You can literally write future-proof CSS and forget old preprocessor specific syntax.

— http://cssnext.io

In addition, cssnext also includes a ton of useful features right out of the box. The full list of features can be found here.

Some personal favourites of mine are the use of custom selectors, automatic vendor prefixing, nesting and the new color() function. It makes sense to use this future-proof syntax now, and remove cssnext from the equation once browsers catch up.

Back to the task. Let’s run through exactly what is happening here:

  • Grab our source files
  • Pipe our files through postcss and cssnext transpiling them down to regular ol’ CSS
  • Save CSS to destination folder
  • Reload browser

Bundle and Minify JavaScript

When dealing with our JavaScript, we’re going to use a very similar piping system to that of our CSS task. We’re also going to make use of Browserify to leverage the power of requiring modules installed via npm. Browserify also bundles our JS libraries for us, and renders them out as a single file which we will then minify.

gulp.task('js', function () {
  return browserify({
    entries: './src/js/app.js',
    debug: true
  })
  .bundle()
  .pipe(source('app.js'))
  .pipe(buffer())
  .pipe(sourcemaps.init({loadMaps: true}))
  .pipe(uglify())
    .on('error', gutil.log)
  .pipe(sourcemaps.write('./'))
  .pipe(gulp.dest('./Build/js'))
  .pipe(reload({stream: true}));
});

Let’s break this down again, line by line:

  • Define our source file
  • Bundle our JS code and its modules with Browserify
  • Create a vinyl object out of our bundled JS
  • Convert vinyl object to a buffered vinyl using the vinyl-buffer plugin
  • Create our source maps
  • Minify our JS using gulp-uglify
  • Embed source maps in the source file
  • Save app.js to our ./Build directory
  • Reload browser

Requiring Power

I just want to briefly touch on the beauty of Browserify here, and the sheer power it brings by allowing you to require() your own modules with ease — especially modules that have been installed with package managers, such as npm. 2

To show this off in action, let’s illustrate how easy it is to get an Angular application up and running. We’re already using npm, so let’s install AngularJS with it.

npm install angular

Now that we have Angular installed, we’ll require it at the top of our .js file and wire together a basic application.

(function() {
  var angular = require('angular');

  angular.module('gulpZeroApp', [])
  .controller('mainCtrl', ['$scope',
    function($scope) {
      $scope.greeting = "Hello Gulp, love Angular!";
    }
  ]);
})();

Painless.

Watch This, Watch That

Gulp is pretty good at this task running thing, huh? Time to hand over more responsibility.

I’d like Gulp to watch a certain few directories — directories where I know the bulk of our changes will occur.

gulp.task('watch', function() {
  gulp.watch('./src/*.html', ['html']);
  gulp.watch(['./src/css/*.css', './src/css/**/*.css'], ['css']);
  gulp.watch('./src/js/*.js', ['js']);
});

Take note of those gulp.watch lines. This is where Gulp will keep watch for any changes in those folders, and when a change is detected (for example, on a save) it will run the relevant task.

If you remember, at the tail end of our 'html', 'sass' and 'js' tasks we are using BrowserSync’s .reload() function. This comes in handy because when we watch for changes and Gulp runs our task, the last thing each of these tasks do is inform the browser to refresh itself, saving us from manually mashing on ⌘ + R to see our changes.

The Default Task

Finally, let’s define our default task.

gulp.task('default', ['serve', 'html', 'css', 'js', 'watch']);

The default task is automatically mapped to the gulp command and when executed, runs every single one of our tasks (serve, html, css, js and watch).

Now in the real world, you would almost definitely write separate tasks for serving up a local version of your site and compiling a static build folder; but in the interest of not overcomplicating this tutorial, I’ve decided to leave this part out.

No Turning Back Now

I tried to keep this introduction to Gulp as just that, an introduction. I hope what I’ve gone over provides you with a basic understanding of what Gulp is, what you can do with it, and hopefully a glimpse into how far you can stretch it. If not, I’ve provided some links below.

When I began using Gulp, I started by adapting a lot of existing Gulp recipes to suit my workflow, and encourage you to do the same. Some of the Gulp generators on Yeoman 3 are a good place to start, and give a broader idea of what else Gulp is capable of (unit testing, image minification, etc.). Of course, feel free to adapt my Gulp Zero project over here on Github.

Lastly, I’ve put together a handful of other Gulp-related resources below, if you so choose to want for some further reading.

  1. Envision our ./Build directory as a cosy home for our newly “gulped” files.

  2. npm or Node Package Manager, is the package manager for Node.js that allows us to install packages via the command line. Gone are the days of downloading a ZIP file, unzipping it, moving the files into your site folder. What animals we once were.

  3. Yeoman is a guy that wears a funny hat. It’s also a pretty popular scaffolding tool for the web.