Barbaric Development Toolbox: Automate Your Front-end Workflow with Gulp - Getting Started
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.
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:
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:
PS> npm install -g gulp-cli
Create a folder where to start learning gulp:
PS> mkdir crazy-experiments-with-gulp
PS> cd crazy-experiments-with-gulp
And try running gulp:
PS> gulp
You’ll probably see the following:
[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:
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:
PS> npm install gulp --save-dev
This should result in a package.json
that should contain gulp as a devDependency
{
// etc...
"devDependencies": {
"gulp": "^3.9.1"
}
// etc..
}
Congratulations! You have Installed Gulp in Your Project!
Now if you run gulp
:
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:
// 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
:
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.
{%blockquote%} 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 {%endblockquote%}
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:
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:
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:
PS> npm install gulp-print --save-dev
And then add it to your build pipeline in your gulpfile.js
:
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:
[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:
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:
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:
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 viagulp.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:
- gulp.js docs
- Great Gulp.js course with John Papa at Pluralsight
- Build a Front-End Build Pipeline From a C# Developer Perspective by the mighty Chris Klug
- Setting Up Continuous Deployment of an ASP.NET App with Gulp from VSTS to an Azure Web App using Scripted Build Definitions
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.
Have a great week ahead!! :)
More Articles In This Series
- Chapter 0: The Basic Ingredients of JavaScriptMancy
- Chapter 1: The Many a One JavaScript Quirks
- Functions
- Object Oriented Programming
- Basics
- ES6
- OOP
- Introduction to OOP in JavaScript for C# Developers
- Summoning Fundamentals: Introduction to OOP In JavaScript – Encapsulation
- Summoning Fundamentals: Introduction to OOP In JavaScript – Inheritance
- Summoning Fundamentals: Introduction to OOP In JavaScript – Polymorphism
- White Tower Summoning: Mimicking C# Classical Inheritance in Javascript
- White Tower Summoning Enhanced: The Marvels of ES6 Classes
- Black Tower Summoning: Object Composition with Mixins
- Safer JavaScript Composition With Traits and Traits.js
- JavaScript Ultra Flexible Object Oriented Programming with Stamps
- Object Oriented JavaScript for C# Programmers
- Tooling
- Data Structures
- Functional Programming
- And more stuff to be shaped out:
- Functional Programming with JavaScript
- Modules
- Asynchronous Programming
- The JavaScript Ecosystem
Written by Jaime González García , dad, husband, software engineer, ux designer, amateur pixel artist, tinkerer and master of the arcane arts. You can also find him on Twitter jabbering about random stuff.