Distributing Projects with Gulp and Bower

Distributing Projects with Gulp & BowerEver wonder why your page displays slowly on Mobile or a Desktop device? This is a very frustrating thing for a user and can cause drop off from your website. The main reason is the load of many blocking css files, images and Javascript files. This can be remedied using a distribution tool and there are a few out there at the moment and I am going to talk about how to work with Javascript libraries and CSS files in development and then get them ready for a production environment.

Gulp is a distribution tool aimed at streamlining your deployment process. This works by using the command line to perform a number of tasks such as moving, minifying and manipulating files into a distribution location for deployment. It achieves these tasks as well as many, many more but for this post I am going to concentrate on the minification in particular as this has a large effect on your page speed. A good tool to use to test your page speed is Google Page Speed which allows you to paste in a url and it performs a short test on your web page for both mobile and Desktop to give it a speed rating. Not only this but it will also flag any user interface issues that need fixing such as small hit areas and viewport issues on mobile.

In order to run Gulp you will need to install Node and the Node Package Manager (npm for short). Node Package Manager allows you to easily install and manage your packages that will

First you will need to install Node using the Node installer which you can find here.

Once you have done this you will need to update npm so you can manage packages on your machine with the latest version.

npm install npm -g

To install gulp inside your web project folder open up your terminal or command line interface and type:

npm install -g gulp

If you come across issues when installing these packages then you will need to make sure you are running the commands as the root user for your machine.

Once Gulp has been installed, create an empty file called gulpfile.js inside your website root folder and then type gulp into your command line making sure you have navigated to your root directory. You should see something like the following:

[16:48:08] Using gulpfile ~/Sites/your-project-web-root/gulpfile.js
[16:48:11] Task 'default' is not in your gulpfile
[16:48:11] Please check the documentation for proper gulpfile formatting

This tells you that Gulp is ready to receive commands inside your Gulp file so you are now ready to start building modules to handle your code minification.

Another tool you can use to manage your Javascript packages is Bower which allows you to directly install javascript frameworks just by typing one command. To install Bower just type:

npm install -g bower

We are now able to install javascript libraries into our project. Lets initialise our Bower project file.

bower init

You will now be prompted with a series of questions so Bower can build a project file. Select the options that are applicable to your project. As an example I filled in the following:

? name: My Web Project
? version: 1.0.0
? description: This is my new web project
? main file: 
? what types of modules does this package expose? 
? keywords: 
? authors: My Name <my-name@my-email-domain.com>
? license: MIT
? homepage: 
? set currently installed components as dependencies? Yes
? add commonly ignored files to ignore list? Yes
? would you like to mark this package as private which prevents it from being accidentally published to the registry? No
{
  name: 'My Web Project',
  version: '1.0.0',
  authors: [
    'My Name <my-name@my-email-domain.com>'
  ],
  description: 'This is my new web project',
  license: 'MIT',
  ignore: [
    '**/.*',
    'node_modules',
    'bower_components',
    'test',
    'tests'
  ]
}
? Looks good? Yes

This will now create a project file in the root of your web directory called bower.json.

This file will be used to store all of the javascript packages that you will want to use in your web project.

Lets install JQuery

bower install jquery --save

This will now add JQuery to your project root inside of the bower_components folder. Not only that but it will also create it as a dependancy in your bower.json file. Adding --save to your install command will save the dependancy into your bower.json file

{
  "name": "My Web Project",
  "version": "1.0.0",
  "authors": [
    "My Name <my-name@my-email-domain.com>"
  ],
  "description": "This is my new web project",
  "license": "MIT",
  "ignore": [
    "**/.*",
    "node_modules",
    "bower_components",
    "test",
    "tests"
  ],
  "dependencies": {
    "jquery": "~2.1.4"
  }
}

After this initial setup you can easily install any packages you like just by running:

bower install your-selected-js-package --save

The general rule of thumb is to develop using the unminified javascript files and then use a distribution tool to minify all your code and build it out to a distribution directory.

Create an assets directory in the route of your web directory and add folders css, js & images to this folder.


Create a javascript file in assets/js, call it app.js and add the following:

//wait for the jquery document ready event
$(document).ready(function(){
    //create html
    var html = "<p>Look at my amazing web page!</p>";
    //add my html to the page
    $("#my-content").html(html);
    //add a console log, just because I can!
    console.log("This is my log message but I don't want it to appear in my production environment");
});

Next lets add some images to our images directory, does not matter what images but I have added some rather large screen grabs generated on my Mac!

Next lets create a simple CSS file and add it to assets/css as styles.css:

/* My CSS File */
/* Body styles */
body{
    background-color: #13e3eb; /* What a horrible colour, who on earth would use this in a web application! */
    margin: 0; /* Get rid of those pesky margins */
}
/* paragraph styles */
p{
    color: #FFF;
    font-size: 14px;
    margin: 10px;
}

Lastly, lets add create an index.html page adding it to the root of our website:

Add the following code:

<!DOCTYPE html>
<html dir="ltr" lang="en-US">
  <head>
      <title>My Website</title>
    <meta name="description" content="This is my awesome website!">
    <script>
        /** @license MIT License (c) Heyday Digital */
        (function(e){e(function(){return function(e,n,t){var o,c,i,r=document.createElement("script"),a=document.getElementsByTagName("script")[0];c=function(e){r.onload=r.onerror=r.onreadystatechange=e},i=function(){c(null),clearTimeout(o),n()},r.src=e,n&&(t&&(o=setTimeout(i,t)),c(function(){var e=this.readyState;e&&"complete"!==e&&"loaded"!==e||i()})),a.parentNode.insertBefore(r,a)}})})("function"==typeof define?define:function(e){this.asyncLoad=e()});
    </script>
  </head>
  <body>
      <div id="my-content"></div>
      <!-- build:js -->
      <script type="text/javascript" src="/bower_components/jquery/dist/jquery.js"></script>
      <script type="text/javascript" src="/assets/js/app.js"></script>
      <!-- endbuild -->
      <!-- build:css -->
      <link async href="/assets/css/styles.css" rel="stylesheet">
      <!-- endbuild -->
  </body>
</html>

You will notice some code in this html. Firstly the chunk of Javascript below:

/** @license MIT License (c) Heyday Digital */
        (function(e){e(function(){return function(e,n,t){var o,c,i,r=document.createElement("script"),a=document.getElementsByTagName("script")[0];c=function(e){r.onload=r.onerror=r.onreadystatechange=e},i=function(){c(null),clearTimeout(o),n()},r.src=e,n&&(t&&(o=setTimeout(i,t)),c(function(){var e=this.readyState;e&&"complete"!==e&&"loaded"!==e||i()})),a.parentNode.insertBefore(r,a)}})})("function"==typeof define?define:function(e){this.asyncLoad=e()});

This chunk of code, developed by Heyday Digital enables you to asynchronously load js into your page so that it does not block the loading of the page at runtime. We place the code inline so we do not need to make a http request that will block the page load.

Next you will notice a series of html comments such as build:js and build:css. These will be used by the gulp module gulp-html-replace to take out the script tags, and add in our asynchronous load for production.

Once we have our site we are now ready to start putting together our Gulp profile. Lets start by installing some modules to handle our distribution.

npm install -g gulp-cssmin gulp-concat gulp-imagemin gulp-uglify gulp-strip-debug run-sequence gulp-html-replace rimraf

Once you have setup these modules you will be able to use them to perform deployment actions to manage your code. You can access these and many more modules at http://gulpjs.com/plugins/.

Once our modules have been installed we write a series of tasks that we can call directly from the command line. The great thing about Gulp is that you can break these up and call them separately giving you a way to isolate tasks. For example, if you want to just minify your CSS and JS then you can just call this separately rather than build the whole deployment again.

Each task uses the following syntax in a Gulp profile:

gulp.task('my-task-name', function(  ) {
    //my task commands here
});

You can then simply call this task directly from the command line like so:

gulp my-task-name

Lets create a Gulp profile to handle the deployment of our files. Add the following code to your gulpfile.js file created earlier in your project directory.

//include our modules so we can use them
var gulp = require('gulp'),
    cssmin = require('gulp-cssmin'),
    concat = require('gulp-concat'),
    imagemin = require('gulp-imagemin'),
    replace = require('gulp-replace'),
    uglify = require('gulp-uglify'),
    stripDebug = require('gulp-strip-debug'),
    runSequence = require('run-sequence'),
    htmlreplace = require('gulp-html-replace'),
    rimraf = require('rimraf');
//distribution directory - files inside this folder are
//used for the main production deployment  
var distFolder = './dist/';
//path to our images
var imgFiles = [
  './assets/images/**/*.{gif,png,jpg}'
];
//path to our main javascript file
var jsFiles = [
  './assets/js/**/*.js'
];
//make sure that the js files are in the correct runtime order
var jsFilesToBuild = [ 
    'bower_components/jquery/dist/jquery.js', 
    'assets/js/app.js' 
];
//path to our html file
var htmlFiles = [
  './index.html'
];
//task to minify our code
gulp.task('clean', function( done ) {
    //remove the distribution folder
    rimraf(distFolder, done);
});
//task to minify our code
gulp.task('minify-code', function() {
    //minify our css for production
    gulp.src('assets/css/styles.css')
        .pipe(cssmin())
        .pipe(concat('styles.min.css'))
        .pipe(gulp.dest(distFolder + 'assets/css'));
    //minify our js for production
    gulp.src( jsFilesToBuild )
        .pipe(stripDebug())
        .pipe(uglify())
        .pipe(concat('app.min.js'))
        .pipe(gulp.dest(distFolder + 'assets/js'));
});
//task to minify our images
gulp.task('minify-images', function() {
    //minifies a series of images
    // - Takes all images in our assets/images folder
    // - Minifies our images to use progressive lossless compression
    // - Copies all of our images to the distribution directory
    gulp.src( imgFiles )
        .pipe(imagemin({
            progressive: true
        }))
        .pipe(gulp.dest(distFolder + 'assets/images'));
});
//task to minify our code
gulp.task('move', function() {
    //move the html page and add the build code for the js and CSS
    gulp.src( htmlFiles )
        .pipe(htmlreplace({
            'js': '<script type="text/javascript"> asyncLoad( "/assets/js/app.min.js"); </script>',
            'css': '<link async href="/assets/css/styles.min.css" rel="stylesheet">'
        }))
        .pipe(gulp.dest(distFolder));
});
//builds whole distribution directory
gulp.task('build', function( done ) {
    // run sequence of tasks
    // - clean the distribution folder
    // - minify the CSS & JS code
    // - move the html and add new declarations to minified code
    runSequence('clean', ['minify-images', 'minify-code', 'move'], done);
});

Now run:

You can then simple call this task directly from the command line like so:

gulp build

You should see something similar to the following:

[14:52:00] Using gulpfile ~/Sites/test-npm/gulpfile.js
[14:52:00] Starting 'build'...
[14:52:00] Starting 'clean'...
[14:52:00] Finished 'clean' after 3.26 ms
[14:52:00] Starting 'minify-images'...
[14:52:00] Finished 'minify-images' after 6.57 ms
[14:52:00] Starting 'minify-code'...
[14:52:00] Finished 'minify-code' after 6.3 ms
[14:52:00] Starting 'move'...
[14:52:00] Finished 'move' after 2.89 ms
[14:52:00] Finished 'build' after 21 ms
[14:52:03] gulp-imagemin: Minified 2 images (saved 37.57 kB - 4.3%)

You will also notice that Gulp has created a folder called /dist inside the root of your project. Gulp has now created a deployment version of your website with your CSS, JS & images all minified and your HTML has been improved to load your Javascript using asynchronous loading.

You can also run these tasks in isolation. For example if we just want to make a change to our Javascript file we can do:

gulp minify-code

This is just a very simple deployment process. There are many, many more modules that will enable you to streamline your sites production including building your SASS & LESS CSS files, live reloading when changes are made to your project, auto prefixing for CSS & the list goes on.

Happy building!