Barbaric Development Toolbox: Automate Your Front-end Workflow With Gulp - Getting Started

| Comments

The Mastering the Arcane Art of JavaScript-mancy series are my humble attempt at bringing my love for JavaScript to all other C# developers that haven’t yet discovered how awesome this language and its whole ecosystem are. These articles are excerpts of the super duper awesome JavaScript-Mancy book a compendium of all things JavaScript for C# developers.

Modern web development is hard. Depending on your environment, your preferences, needs and goals there’s a thousand and one steps from source code to a production ready application.

You may want to use TypeScript or ES2015 for the obvious development benefits but then you need to transpile either one to a version of JavaScript that can run in the browser. You may want to use SASS or LESS, again for the much better development experience they provide, but then you need to transpile them to CSS as well. You need to manage your third party libraries and reference them in your app, and optimize the size of your images for the web, and bundle, minify your assets, add cache busting, etc, etc.

These are a lot of steps that you probably don’t want to keep in your head or in a checklist somewhere. You want to make them an intrinsic part of your development workflow and automate them so that they are reproduceable and reusable by all the members within your team (and even by the continuous integration and delivery infrastructure).

That’s were Gulp and other popular task runners/managers come in. Gulp helps you automate your workflow, make it explicit and share it within your team by providing an API to create and compose tasks. These tasks could be anything from copying files to a distribution folder, to transpiling ES2015, to removing unused CSS classes, etc. You can either build your own task or take advantage of the humongous community that already exist around Gulp and provides access to any task that you can imagine via plugins.

An image of gulp that reads Automate and enhance your workflow with gulp

Sounds interesting? Then let’s get started.

Getting Started With Gulp

Installing Gulp in Your Project

As many other front-end development tooling, gulp runs on node.js. This means that you’ll need to install node in your machine before you can start using gulp. If node is not a part of your development environment then take a look at this article on front-end development tooling where I guide you on how to do it in OSX and Windows.

Once you have node and npm in your environment you’ll be able to install gulp itself.

For the Node Savvy

Install gulp-cli globally and gulp in your project:

1
2
3
PS> npm install -g gulp-cli
PS> npm init
PS> npm install gulp --save-dev

For the Node Beginner

Let’s start by installing the gulp command line interface globally. Open your favorite command line (PowerShell or Cmder work fine) and type:

1
PS> npm install -g gulp-cli

Create a folder where to start learning gulp:

1
2
PS> mkdir crazy-experiments-with-gulp
PS> cd crazy-experiments-with-gulp

And try running gulp:

1
PS> gulp

You’ll probably see the following:

1
2
[20:48:11] Local gulp not found in .../crazy-experiments-with-gulp
[20:48:11] Try running: npm install gulp

Which gives you a great pointer to the fact that you need to install gulp in your project. We’re on the right path! Yey!

Before you install gulp you want to create a package.json manifest file for your project. Why is that? You may ask. The answer is that package.json lets you define the development dependencies of your project. Once defined you can save them in your favorite source control system so other members of your team or arbitrary people that happens to stumble upon your code can also enjoy the beauty of gulp.

You can create the manifest by typing the following:

1
PS> npm init

This will start a wizard that will guide you through the process of creating a manifest. Since you don’t plan to publish a new library to npm you can just set all default options by just pressing ENTER until the end of the wizard. This will generate a package.json with the correct format to which you can add gulp as development dependency by typing:

1
PS> npm install gulp --save-dev

This should result in a package.json that should contain gulp as a devDependency

1
2
3
4
5
6
7
{
  // etc...
  "devDependencies": {
    "gulp": "^3.9.1"
  },
  // etc..
}

Congratulations! You have Installed Gulp in Your Project!

Now if you run gulp:

1
2
PS> gulp
[21:03:56] No gulpfile found

Which highlights the very important fact that gulp expects you to have a gulpfile.js file that will contain your automated tasks.

Creating Your First Task

Let’s create a very simple gulp configuration file. Create a gulpfile.js in the root folder of your project, open it in your favorite editor, and type the following:

1
2
3
4
5
6
7
// get access to the gulp API
var gulp = require('gulp');

// create a task
gulp.task('puny-human', function(){        // gulp.task(taskName, callback)
    console.log('Puny Human!!!!');
});

Awesome! You have defined your first gulp task. You can execute it from the command line (or using the Task Runner Explorer for Visual Studio) by typing its name after gulp:

1
2
3
4
5
PS> gulp puny-humans
[21:20:43] Using gulpfile ~/GitHub/barbaric-toolbox-gulp/gulpfile.js
[21:20:43] Starting 'puny human'...
Puny humaaaan
[21:20:43] Finished 'puny human' after 154 μs

The gulp.task is one of core functions of the gulp API that let’s you define tasks by providing the name of the task and a function to execute when the task is invoked.

It’s All About Streams of Files

Front-end task automation has a lot to do with managing files: Getting files from one place, transforming them, improving them, massaging them and putting them in some other place. The way gulp chooses to model these files that go through different kinds of transformations is as a stream.

In computer science, a stream is a sequence of data elements made available over time. A stream can be thought of as items on a conveyor belt being processed one at a time rather than in large batches

The way you create a stream of files with gulp is by using gulp.src, and the way you write the files within the stream to some place of your choice is via gulp.dest.

Let’s imagine that you’ve built a web application and you have a bunch of javascript files within the app/js folder. You want to get these files, minify, bundle them and then copy them to a build folder build. Well, you can start by creating a simpler task that just copies the files:

1
2
3
4
gulp.task('build', function(){
    return gulp.src('app/**/*.js')          // gulp.src(glob)
            .pipe(gulp.dest('build'));      // gulp.dest(path)
});

If you run the task with gulp build you’ll be able to verify how there’s a new build folder in your project folder, and how every js file within app/js has been copied over to build/js.

An interesting thing to point here is how gulp is going to determine which paths to use when copying. In the expression gulp.src('app/**/*.js') the ** separates the base path app to the relative path that’s going to be copied over to the destination path at build. That’s why the a file in app/js/sandwich.js would be copied to build/js/sandwich.js and not to build/app/js/sandwich.js or to build/sandwich.js. Another interesting thing to notice is how we return the stream from the function within gulp.task. We do that because it will enable us to compose tasks together in the future.

Once we have defined the origin and destination of our files we could add processing steps to the pipeline like minification or bundling. For instance:

1
2
3
4
5
6
7
8
gulp.task('build', function(){
    return gulp.src('app/**/*.js')          // gulp.src(glob)
            .pipe(minify())
            .pipe(bundle())
            .pipe(cacheBust())
            .pipe(addBellsAndWhistles())
            .pipe(gulp.dest('build'));      // gulp.dest(path)
});

We will take a look at both of these later in the series, now, let’s go back to basics!

Help to Visualize the Stream

A great way to visualize the files as they move through the stream is the gulp-print plugin. You can install through npm:

1
PS> npm install gulp-print --save-dev

And then add it to your build pipeline in your gulpfile.js:

1
2
3
4
5
6
7
8
var gulp = require('gulp'),
    print = require('gulp-print');

gulp.task('build', function(){
    return gulp.src('app/**/*.*')
            .pipe(print())
            .pipe(gulp.dest('build'));
});

Now you can see the stream of files flowing throw the pipeline. If you type gulp build you’ll be able to see the following which is super helpful for debugging and understanding how gulp works:

1
2
3
4
5
6
7
8
9
[21:57:28] Using gulpfile ~/GitHub/barbaric-toolbox-gulp/gulpfile.js
[21:57:28] Starting 'build'...
[21:57:28] app/css/styles.css
[21:57:28] app/templates/footer.html
[21:57:28] app/templates/header.html
[21:57:28] app/templates/main.html
[21:57:28] app/js/codes.js
[21:57:28] app/js/more-codes.js
[21:57:28] Finished 'build' after 49 ms

Doing Stuff When Files Change

We started this blog with automation and we wouldn’t be making automation justice if you had to run every single task manually. That’s why gulp offers a way to watch files for changes and then trigger tasks automatically for you. Common use case? Change a TypeScript or ES6 file and get it automatically transpiled into JavaScript and copied to the right folder so that you can see your changes instantly or nearly instantly in the browser.

You can make gulp watch on file changes through the gulp.watch function. Let’s stick with the basics for now and just trigger a build task whenever a file changes:

1
2
3
gulp.task('watch', function(){
    gulp.watch('app/**/*.*', ['build']);
});

Whenever you run gulp watch gulp will start watching the files that match the glob that you specify (in this case all files within the app folder and subfolders) and trigger a build whenever any of them changes.

Setting a Default Task

We are nearing the end of this introduction to gulp but I wanted to leave you with yet another tidbit of knowledge. Do you know what happens if you just type gulp inside your project? Let’s try it:

1
2
3
4
PS> gulp
[22:28:51] Using gulpfile ~/GitHub/barbaric-toolbox-gulp/gulpfile.js
[22:28:51] Task 'default' is not in your gulpfile
[22:28:51] Please check the documentation for proper gulpfile formatting

What happens is that gulp complains that there’s no default task defined in your configuration file. Well you can define a default task to be executed whenever you type gulp. For instance, it could be our build task:

1
gulp.task('default', ['build']);

Now any time that you type gulp the build task will be executed. Yes! You’ve saved yourself from typing 6 characters! Think of all the things you can do with that free time!!!

Summary

So I hope that you have enjoyed getting started with gulp. In this article you learned:

  • how to install gulp in a project,
  • how to create a simple task to log something funny,
  • how gulp works with streams of files, grabbing files from a source of your choice with gulp.src, transforming them in different ways and putting them back to a destination via gulp.dest
  • how you can use the gulp-print plugin to visualize the file stream and debug a task
  • how to listen to file changes and trigger tasks through gulp.watch
  • and how to define a default task and save yourself precious life energy

If you want to take a look at the complete build pipeline for this article check the Barbaric-Toolbox-Gulp repository at GitHub.

Want to Learn More About Gulp?

In the upcoming weeks I am going to be adding small elements to the build pipeline but if you can’t get enough of gulp here are some other interesting resources:

Interested in Learning More JavaScript? Buy the Book!

Are you a C# Developer interested in learning JavaScript? Then take a look at the JavaScript-mancy book, a complete compendium of JavaScript for C# developers.

a JavaScriptmancy sample cover

More Articles in These Series

Comments