Gulp is one of the most exciting tools I've added to my front-end web development belt over the last couple of years. I primarily use it to automate my front-end workflow and for building distributable assets, however the possible uses go far beyond that. Add NPM into the mix, for package management, and baby you got a stew going.

Below, I'll describe a basic setup of using Gulp and NPM for creating a simple bootstrap web app. If you want to skip straight to the good stuff, I have a 'starter project' template at my GitHub: https://github.com/gaw508/bootstrap-starter-project

NPM

If you're not familiar with NPM - Node Package Manager - it's the package manager for the Node.js language, i.e. a tool for managing JavaScript libraries and packages (usually from the NPM registry). Despite being primarily for the Node.js language, it also contains many packages for front-end web development, including jQuery, Bootstrap and many others.

The NPM configuration in your project is defined within a package.json file. This file can contain numerous configuration options, including - most importantly - which packages are required for the project. Also, if you wanted to contribute a package to the NPM registry, this file would be used to put information about your package.

You'll need both Node.js and NPM installed to use Gulp and for the setup described below. To install Node.js and NPM, visit https://nodejs.org

Gulp

Gulp is a fantastic little tool for automating your workflow - done by writing simple JavaScript to manipulate streams of files. While Gulp can be used for an enormous number of tasks, my use of it is generally restricted to front-end web development workflow.

Two important concepts in Gulp are tasks and watchers. Tasks are units of code which can be executed, either on the command line (using the gulp CLI tool) or from within other tasks and watchers. Watchers 'watch' for changes to specific files and directories, and trigger a callback - for example running a task.

Within your project, Gulp code is contained within the gulpfile.js file. You can include other JS files and packages in your gulpfile, but for simple projects you will likely define all of your tasks and watchers here.

Gulp can be installed globally by running:

npm install gulp-cli -g
npm install gulp -D
gulp —help

Setting up the project

The project we're going to create is a simple one-page web app, using Bootstrap and jQuery (exciting stuff, eh?). All of our JS and CSS assets will be concatenated, minified, and copied into our public html directory, along with our static assets, i.e. images.

The project's file structure will be:

project_root/
    src/                        # Source assets
        css/                    # Source CSS files
            blah_styles.css
        js/                     # Source JS files
            blah_script.js
        images/                 # Source image files
            pretty.png
    web/                        # The web root/public HTML
        dist/                   # Distributable assets - populated by gulp
        index.html              # App HTML file
    .gitignore
    gulpfile.js                 # Gulpfile for project
    package.json                # NPM configuration

In the following sections we'll work through the contents of the files.

Requiring our packages with NPM

The first thing we'll do is create our package.json file. To start with this can just be an empty JSON object:

{

}

Now we need to install the packages for our project:

  • Gulp: The Gulp tool.
  • jQuery: JavaScript library for our web app.
  • Bootstrap: HTML/CSS/JS framework for our web app
  • Gulp Concat: A package for concatenating files in Gulp
  • Gulp Minify CSS: A package for minifying CSS files in Gulp
  • Gulp Uglify: A package for minifying JS files in Gulp
  • Live Server: Simple HTTP Server for testing our web app

It's one simple command to install them all:

npm install --save bootstrap jquery gulp gulp-concat gulp-minify-css gulp-uglify live-server

You'll notice two things: first, the contents of package.json has been updated with the names of all of the packages; second, all of the packages are installed into a new directory called node_modules. We don't want to include the files in node_modules in our version control, only the references to them in package.json. For git, we can add this directory to our project's .gitignore file.

.gitignore

node_modules

Writing our gulpfile

Now we have all of our required packages, we can write our build script in gulpfile.js. The first thing to do is require all of the gulp tools we want to use:

var gulp = require('gulp'),
    uglify = require('gulp-uglify'),
    concat = require('gulp-concat'),
    minifyCSS = require('gulp-minify-css');

Next, we will write our CSS task:

gulp.task('css', function() {
    gulp.src([
            'node_modules/bootstrap/dist/css/bootstrap.css',
            'src/css/**/*.css'
        ])
        .pipe(minifyCSS())
        .pipe(concat('style.css'))
        .pipe(gulp.dest('web/dist/css'));
});

gulp.task() is the function used to define a task, accepting two arguments, the task name and the function to call when the task is run.

gulp.src() creates a stream of files, which can be piped into different tools. You'll notice that the bootstrap css file is added to the stream, along with any CSS file within the source CSS directory. The file stream is first piped into minifyCSS(), which minifies each of the CSS files individually. Then the stream is piped into concat(), which concatenates all of the files into a single file, called style.css. The final pipe is into gulp.dest(), which outputs our concatenated file into the web/dist/css directory. Simple stuff!

The next task to write is the JS task, which is very similar to the CSS task:

gulp.task('js', function() {
    gulp.src([
            'node_modules/jquery/dist/jquery.js',
            'node_modules/bootstrap/dist/js/bootstrap.js',
            'src/js/**/*.js'
        ])
        .pipe(uglify())
        .pipe(concat('script.js'))
        .pipe(gulp.dest('web/dist/js'));
});

Again, gulp.src() creates a file stream including jQuery, the Bootstrap JS file, as well as any JS file within the source JS directory. This is then piped into uglify, the JS minifying tool, concatenated, and outputted to web/dist/js/script.js.

Next is the image task, which simply copies images from our source directory into our distributable directory. This task is very simple for the purposes of this article, but could be expanded to resize images, watermark them or combine them into a sprite.

gulp.task('images', function() {
    gulp.src([
            'src/images/**/*'
        ])
        .pipe(gulp.dest('web/dist/images'));
});

You'll notice the stream of image files is simply piped straight into the distributable images dir without any modifications.

The final task is the default task. This is the task which is run if the Gulp CLI tool is run with no arguments, and will likely be the task you run most often. For our project, the default task will simply run all of our above tasks, one by one.

gulp.task('default', function() {
    gulp.run('js', 'css', 'images');
});

Now we have defined all of our 'standard' tasks, we can write a task to start watching for file changes. We'll set it up so that if there are any changes to CSS, JS or image files, the relevant task will be run automatically.

gulp.task('watch', function() {
        gulp.run('default');

        gulp.watch('src/css/**/*.css', function(event) {
            console.log('File ' + event.path + ' was ' + event.type + ', running tasks...');
            gulp.run('css');
        });

        gulp.watch('src/js/**/*.js', function(event) {
            console.log('File ' + event.path + ' was ' + event.type + ', running tasks...');
            gulp.run('js');
        });

        gulp.watch('src/images/**/*', function(event) {
            console.log('File ' + event.path + ' was ' + event.type + ', running tasks...');
            gulp.run('images');
        });
});

We've first created a task called 'watch', which, when run, will start all of our watchers. Next the default task is run, to ensure any existing changes are built before starting watchers. After this, three watchers are defined:

  • On source CSS files - calling the css task
  • On source JS files - calling the js task
  • On source image files - calling the images task

Next we'll finish creating our simple HTML, CSS and JS files, before looking into how we can run our Gulp tasks.

Filling in the blanks

In order to make our web app, we need to (quickly) write an HTML file, a JS file and a CSS file, plus adding an image - this is so we can see how our Gulp build process works.

src/css/blah_styles.css

.my-container {
    background: #dedede;
}

src/js/blah_script.js

$(document).ready(function() {
    console.log('Ready!');
});

src/images/yeah.png

Any old image file you have knocking about...

web/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <title>NPM and Gulp Tutorial</title>

    <link href="dist/css/style.css" rel="stylesheet">
</head>
<body>

    <div class="container my-container">
        <div class="page-header">
            <h3>NPM and Gulp Tutorial</h3>
        </div>

        <div>
            <p>Content</p>
            <img src="dist/images/yeah.png">
        </div>
    </div>

    <script src="dist/js/script.js"></script>
</body>
</html>

Notice how in the HTML file we reference the output files of our build process, and not the source files.

Running tasks

We are now all set for building our distributable assets, by running gulp. Open up a command line window and go to the root directory of the project. Then run:

gulp

This runs the default task in our gulpfile.js - which then runs our CSS, JS and images tasks. Once complete, you will notice three new files:

  • web/dist/css/style.css - our concatenated and minified CSS file
  • web/dist/js/script.js - our concatenated and minified JS file
  • web/dist/images/yeah.png - our copied image file

To preview our web app, we can use the live server package we installed earlier:

live-server web/

Voila! Your browser will open and the web app will appear.

If you wanted to run a single task, say the CSS task, you could run:

gulp css

This would only concatenate and minify CSS files, without touching JS and image files.

To start the watchers, run:

gulp watch

Now any time you make a change to any file under src/js, src/css or src/images they will be automatically built.

Next steps

Now that your front-end workflow is 10x more efficient you have no excuses, go and ship something cool - Go! Now!

You can find the tutorial code at https://github.com/gaw508/tutorials/tree/master/gulp-and-npm and a 'starter project' template at https://github.com/gaw508/bootstrap-starter-project