Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
All Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletter Hub
Free Learning
Arrow right icon
timer SALE ENDS IN
0 Days
:
00 Hours
:
00 Minutes
:
00 Seconds

Deployment Preparations

Save for later
  • 23 min read
  • 08 Jul 2015

article-image

In this article by Jurie-Jan Botha, author of the book Grunt Cookbook, has covered the following recipes:

  • Minifying HTML
  • Minifying CSS
  • Optimizing images
  • Linting JavaScript code
  • Uglifying JavaScript code
  • Setting up RequireJS

(For more resources related to this topic, see here.)

Once our web application is built and its stability ensured, we can start preparing it for deployment to its intended market. This will mainly involve the optimization of the assets that make up the application. Optimization in this context mostly refers to compression of one kind or another, some of which might lead to performance increases too.

The focus on compression is primarily due to the fact that the smaller the asset, the faster it can be transferred from where it is hosted to a user's web browser. This leads to a much better user experience, and can sometimes be essential to the functioning of an application.

Minifying HTML

In this recipe, we make use of the contrib-htmlmin (0.3.0) plugin to decrease the size of some HTML documents by minifying them.

Getting ready

In this example, we'll work with the a basic project structure.

How to do it...

The following steps take us through creating a sample HTML document and configuring a task that minifies it:

  1. We'll start by installing the package that contains the contrib-htmlmin plugin.
  2. Next, we'll create a simple HTML document called index.html in the src directory, which we'd like to minify, and add the following content in it:
    <html>
    <head>
       <title>Test Page</title>
    </head>
    <body>
       <!-- This is a comment! -->
       <h1>This is a test page.</h1>
    </body>
    </html>
  3. Now, we'll add the following htmlmin task to our configuration, which indicates that we'd like to have the white space and comments removed from the src/index.html file, and that we'd like the result to be saved in the dist/index.html file:
    htmlmin: {
    dist: {
       src: 'src/index.html',
       dest: 'dist/index.html',
       options: {
         removeComments: true,
         collapseWhitespace: true
       }
    }
    }

    The removeComments and collapseWhitespace options are used as examples here, as using the default htmlmin task will have no effect. Other minification options can be found at the following URL:

    https://github.com/kangax/html-minifier#options-quick-reference

  4. We can now run the task using the grunt htmlmin command, which should produce output similar to the following:
    Running "htmlmin:dist" (htmlmin) task
    Minified dist/index.html 147 B ? 92 B
  5. If we now take a look at the dist/index.html file, we will see that all white space and comments have been removed:
    <html>
    <head>
       <title>Test Page</title>
    </head>
    <body>
       <h1>This is a test page.</h1>
    </body>
    </html>

Minifying CSS

In this recipe, we'll make use of the contrib-cssmin (0.10.0) plugin to decrease the size of some CSS documents by minifying them.

Getting ready

In this example, we'll work with a basic project structure.

How to do it...

The following steps take us through creating a sample CSS document and configuring a task that minifies it.

  1. We'll start by installing the package that contains the contrib-cssmin plugin.
  2. Then, we'll create a simple CSS document called style.css in the src directory, which we'd like to minify, and provide it with the following contents:
    body {
    /* Average body style */
    background-color: #ffffff;
    color: #000000; /*! Black (Special) */
    }
  3. Now, we'll add the following cssmin task to our configuration, which indicates that we'd like to have the src/style.css file compressed, and have the result saved to the dist/style.min.css file:
    cssmin: {
    dist: {
       src: 'src/style.css',
       dest: 'dist/style.min.css'
    }
    }
  4. We can now run the task using the grunt cssmin command, which should produce the following output:
    Running "cssmin:dist" (cssmin) task
    File dist/style.css created: 55 B ? 38 B
  5. If we take a look at the dist/style.min.css file that was produced, we will see that it has the compressed contents of the original src/style.css file:
    body{background-color:#fff;color:#000;/*! Black (Special) */}

There's more...

The cssmin task provides us with several useful options that can be used in conjunction with its basic compression feature. We'll look at prefixing a banner, removing special comments, and reporting gzipped results.

Prefixing a banner

In the case that we'd like to automatically include some information about the compressed result in the resulting CSS file, we can do so in a banner. A banner can be prepended to the result by supplying the desired banner content to the banner option, as shown in the following example:

cssmin: {
dist: {
   src: 'src/style.css',
   dest: 'dist/style.min.css',
   options: {
     banner: '/* Minified version of style.css */'
   }
}
}

Removing special comments

Comments that should not be removed by the minification process are called special comments and can be indicated using the "/*! comment */" markers. By default, the cssmin task will leave all special comments untouched, but we can alter this behavior by making use of the keepSpecialComments option.

The keepSpecialComments option can be set to either the *, 1, or 0 value. The * value is the default and indicates that all special comments should be kept, 1 indicates that only the first comment that is found should be kept, and 0 indicates that none of them should be kept. The following configuration will ensure that all comments are removed from our minified result:

cssmin: {
dist: {
   src: 'src/style.css',
   dest: 'dist/style.min.css',
   options: {
     keepSpecialComments: 0
   }
}
}

Reporting on gzipped results

Reporting is useful to see exactly how well the cssmin task has compressed our CSS files. By default, the size of the targeted file and minified result will be displayed, but if we'd also like to see the gzipped size of the result, we can set the report option to gzip, as shown in the following example:

cssmin: {
dist: {
   src: 'src/main.css',
   dest: 'dist/main.css',
   options: {
     report: 'gzip'
   }
}
}

Optimizing images

In this recipe, we'll make use of the contrib-imagemin (0.9.4) plugin to decrease the size of images by compressing them as much as possible without compromising on their quality. This plugin also provides a plugin framework of its own, which is discussed at the end of this recipe.

Getting ready

In this example, we'll work with the basic project structure.

How to do it...

The following steps take us through configuring a task that will compress an image for our project.

  1. We'll start by installing the package that contains the contrib-imagemin plugin.
  2. Next, we can ensure that we have an image called image.jpg in the src directory on which we'd like to perform optimizations.
  3. Now, we'll add the following imagemin task to our configuration and indicate that we'd like to have the src/image.jpg file optimized, and have the result saved to the dist/image.jpg file:
    imagemin: {
    dist: {
       src: 'src/image.jpg',
       dest: 'dist/image.jpg'
    }
    }
  4. We can then run the task using the grunt imagemin command, which should produce the following output:
    Running "imagemin:dist" (imagemin) task
    Minified 1 image (saved 13.36 kB)
  5. If we now take a look at the dist/image.jpg file, we will see that its size has decreased without any impact on the quality.

There's more...

The imagemin task provides us with several options that allow us to tweak its optimization features. We'll look at how to adjust the PNG compression level, disable the progressive JPEG generation, disable the interlaced GIF generation, specify SVGO plugins to be used, and use the imagemin plugin framework.

Adjusting the PNG compression level

The compression of a PNG image can be increased by running the compression algorithm on it multiple times. By default, the compression algorithm is run 16 times. This number can be changed by providing a number from 0 to 7 to the optimizationLevel option. The 0 value means that the compression is effectively disabled and 7 indicates that the algorithm should run 240 times. In the following configuration we set the compression level to its maximum:

imagemin: {
dist: {
   src: 'src/image.png',
   dest: 'dist/image.png',
   options: {
     optimizationLevel: 7
   }
}
}

Disabling the progressive JPEG generation

Progressive JPEGs are compressed in multiple passes, which allows a low-quality version of them to quickly become visible and increase in quality as the rest of the image is received. This is especially helpful when displaying images over a slower connection.

By default, the imagemin plugin will generate JPEG images in the progressive format, but this behavior can be disabled by setting the progressive option to false, as shown in the following example:

imagemin: {
dist: {
   src: 'src/image.jpg',
   dest: 'dist/image.jpg',
   options: {
     progressive: false
   }
}
}

Disabling the interlaced GIF generation

An interlaced GIF is the equivalent of a progressive JPEG in that it allows the contained image to be displayed at a lower resolution before it has been fully downloaded, and increases in quality as the rest of the image is received.

By default, the imagemin plugin will generate GIF images in the interlaced format, but this behavior can be disabled by setting the interlaced option to false, as shown in the following example:

imagemin: {
dist: {
   src: 'src/image.gif',
   dest: 'dist/image.gif',
   options: {
     interlaced: false
   }
}
}

Specifying SVGO plugins to be used

When optimizing SVG images, the SVGO library is used by default. This allows us to specify the use of various plugins provided by the SVGO library that each performs a specific function on the targeted files.

Refer to the following URL for more detailed instructions on how to use the svgo plugins options and the SVGO library:

https://github.com/sindresorhus/grunt-svgmin#available-optionsplugins

Most of the plugins in the library are enabled by default, but if we'd like to specifically indicate which of these should be used, we can do so using the svgoPlugins option. Here, we can provide an array of objects, where each contain a property with the name of the plugin to be affected, followed by a true or false value to indicate whether it should be activated. The following configuration disables three of the default plugins:

imagemin: {
dist: {
   src: 'src/image.svg',
   dest: 'dist/image.svg',
   options: {
     svgoPlugins: [
       {removeViewBox:false},
       {removeUselessStrokeAndFill:false},
       {removeEmptyAttrs:false}
     ]
   }
}
}

Using the 'imagemin' plugin framework

In order to provide support for the various image optimization projects, the imagemin plugin has a plugin framework of its own that allows developers to easily create an extension that makes use of the tool they require.

You can get a list of the available plugin modules for the imagemin plugin's framework at the following URL:

https://www.npmjs.com/browse/keyword/imageminplugin

The following steps will take us through installing and making use of the mozjpeg plugin to compress an image in our project. These steps start where the main recipe takes off.

  1. We'll start by installing the imagemin-mozjpeg package using the npm install imagemin-mozjpeg command, which should produce the following output:
    [email protected] node_modules/imagemin-mozjpeg
  2. With the package installed, we need to import it into our configuration file, so that we can make use of it in our task configuration. We do this by adding the following line at the top of our Gruntfile.js file:
    var mozjpeg = require('imagemin-mozjpeg');
  3. With the plugin installed and imported, we can now change the configuration of our imagemin task by adding the use option and providing it with the initialized plugin:
    imagemin: {
    dist: {
       src: 'src/image.jpg',
       dest: 'dist/image.jpg',
       options: {
         use: [mozjpeg()]
       }
    }
    }
  4. Finally, we can test our setup by running the task using the grunt imagemin command. This should produce an output similar to the following:
    Running "imagemin:dist" (imagemin) task
    Minified 1 image (saved 9.88 kB)

Linting JavaScript code

In this recipe, we'll make use of the contrib-jshint (0.11.1) plugin to detect errors and potential problems in our JavaScript code. It is also commonly used to enforce code conventions within a team or project. As can be derived from its name, it's basically a Grunt adaptation for the JSHint tool.

Getting ready

In this example, we'll work with the basic project structure.

How to do it...

The following steps take us through creating a sample JavaScript file and configuring a task that will scan and analyze it using the JSHint tool.

  1. We'll start by installing the package that contains the contrib-jshint plugin.
  2. Next, we'll create a sample JavaScript file called main.js in the src directory, and add the following content in it:

    sample = 'abc';

    console.log(sample);

  3. With our sample file ready, we can now add the following jshint task to our configuration. We'll configure this task to target the sample file and also add a basic option that we require for this example:

    jshint: {

    main: {

       options: {

         undef: true

       },

       src: ['src/main.js']

    }

    }

    Unlock access to the largest independent learning library in Tech for FREE!
    Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
    Renews at €14.99/month. Cancel anytime

    The undef option is a standard JSHint option used specifically for this example and is not required for this plugin to function. Specifying this option indicates that we'd like to have errors raised for variables that are used without being explicitly defined.

  4. We can now run the task using the grunt jshint command, which should produce output informing us of the problems found in our sample file:
    Running "jshint:main" (jshint) task
     
       src/main.js
         1 |sample = 'abc';
             ^ 'sample' is not defined.
         2 |console.log(sample);
             ^ 'console' is not defined.
         2 |console.log(sample);
                         ^ 'sample' is not defined.
     
    >> 3 errors in 1 file

There's more...

The jshint task provides us with several options that allow us to change its general behavior, in addition to how it analyzes the targeted code. We'll look at how to specify standard JSHint options, specify globally defined variables, send reported output to a file, and prevent task failure on JSHint errors.

Specifying standard JSHint options

The contrib-jshint plugin provides a simple way to pass all the standard JSHint options from the task's options object to the underlying JSHint tool.

A list of all the options provided by the JSHint tool can be found at the following URL:

http://jshint.com/docs/options/

The following example adds the curly option to the task we created in our main recipe to enforce the use of curly braces wherever they are appropriate:

jshint: {
main: {
   options: {
     undef: true,
     curly: true
   },
   src: ['src/main.js']
}
}

Specifying globally defined variables

Making use of globally defined variables is quite common when working with JavaScript, which is where the globals option comes in handy. Using this option, we can define a set of global values that we'll use in the targeted code, so that errors aren't raised when JSHint encounters them.

In the following example, we indicate that the console variable should be treated as a global, and not raise errors when encountered:

jshint: {
main: {
   options: {
     undef: true,
     globals: {
       console: true
     }
   },
   src: ['src/main.js']
}
}

Sending reported output to a file

If we'd like to store the resulting output from our JSHint analysis, we can do so by specifying a path to a file that should receive it using the reporterOutput option, as shown in the following example:

jshint: {
main: {
   options: {
     undef: true,
     reporterOutput: 'report.dat'
   },
   src: ['src/main.js']
}
}

Preventing task failure on JSHint errors

The default behavior for the jshint task is to exit the running Grunt process once a JSHint error is encountered in any of the targeted files. This behavior becomes especially undesirable if you'd like to keep watching files for changes, even when an error has been raised.

In the following example, we indicate that we'd like to keep the process running when errors are encountered by giving the force option a true value:

jshint: {
main: {
   options: {
     undef: true,
     force: true
   },
   src: ['src/main.js']
}
}

Uglifying JavaScript Code

In this recipe, we'll make use of the contrib-uglify (0.8.0) plugin to compress and mangle some files containing JavaScript code.

For the most part, the process of uglifying just removes all the unnecessary characters and shortens variable names in a source code file. This has the potential to dramatically reduce the size of the file, slightly increase performance, and make the inner workings of your publicly available code a little more obscure.

Getting ready

In this example, we'll work with the basic project structure.

How to do it...

The following steps take us through creating a sample JavaScript file and configuring a task that will uglify it.

  1. We'll start by installing the package that contains the contrib-uglify plugin.
  2. Then, we can create a sample JavaScript file called main.js in the src directory, which we'd like to uglify, and provide it with the following contents:
    var main = function () {
    var one = 'Hello' + ' ';
    var two = 'World';
     
    var result = one + two;
     
    console.log(result);
    };
  3. With our sample file ready, we can now add the following uglify task to our configuration, indicating the sample file as the target and providing a destination output file:
    uglify: {
    main: {
       src: 'src/main.js',
       dest: 'dist/main.js'
    }
    }
  4. We can now run the task using the grunt uglify command, which should produce output similar to the following:
    Running "uglify:main" (uglify) task
    >> 1 file created.
  5. If we now take a look at the resulting dist/main.js file, we should see that it contains the uglified contents of the original src/main.js file.

There's more...

The uglify task provides us with several options that allow us to change its general behavior and see how it uglifies the targeted code. We'll look at specifying standard UglifyJS options, generating source maps, and wrapping generated code in an enclosure.

Specifying standard UglifyJS options

The underlying UglifyJS tool can provide a set of options for each of its separate functional parts. These parts are the mangler, compressor, and beautifier. The contrib-plugin allows passing options to each of these parts using the mangle, compress, and beautify options.

The available options for each of the mangler, compressor, and beautifier parts can be found at each of following URLs (listed in the order mentioned):

https://github.com/mishoo/UglifyJS2#mangler-options

https://github.com/mishoo/UglifyJS2#compressor-options

https://github.com/mishoo/UglifyJS2#beautifier-options

The following example alters the configuration of the main recipe to provide a single option to each of these parts:

uglify: {
main: {
   src: 'src/main.js',
   dest: 'dist/main.js',
   options: {
     mangle: {
       toplevel: true
     },
     compress: {
       evaluate: false
     },
     beautify: {
       semicolons: false
     }
   }
}
}

Generating source maps

As code gets mangled and compressed, it becomes effectively unreadable to humans, and therefore, nearly impossible to debug. For this reason, we are provided with the option of generating a source map when uglifying our code.

The following example makes use of the sourceMap option to indicate that we'd like to have a source map generated along with our uglified code:

uglify: {
main: {
   src: 'src/main.js',
   dest: 'dist/main.js',
   options: {
     sourceMap: true
   }
}
}

Running the altered task will now, in addition to the dist/main.js file with our uglified source, generate a source map file called main.js.map in the same directory as the uglified file.

Wrapping generated code in an enclosure

When building your own JavaScript code modules, it's usually a good idea to have them wrapped in a wrapper function to ensure that you don't pollute the global scope with variables that you won't be using outside of the module itself.

For this purpose, we can use the wrap option to indicate that we'd like to have the resulting uglified code wrapped in a wrapper function, as shown in the following example:

uglify: {
main: {
   src: 'src/main.js',
   dest: 'dist/main.js',
   options: {
     wrap: true
   }
}
}

If we now take a look at the result dist/main.js file, we should see that all the uglified contents of the original file are now contained within a wrapper function.

Setting up RequireJS

In this recipe, we'll make use of the contrib-requirejs (0.4.4) plugin to package the modularized source code of our web application into a single file.

For the most part, this plugin just provides a wrapper for the RequireJS tool. RequireJS provides a framework to modularize JavaScript source code and consume those modules in an orderly fashion. It also allows packaging an entire application into one file and importing only the modules that are required while keeping the module structure intact.

Getting ready

In this example, we'll work with the basic project structure.

How to do it...

The following steps take us through creating some files for a sample application and setting up a task that bundles them into one file.

  1. We'll start by installing the package that contains the contrib-requirejs plugin.
  2. First, we'll need a file that will contain our RequireJS configuration. Let's create a file called config.js in the src directory and add the following content in it:
    require.config({
    baseUrl: 'app'
    });
  3. Secondly, we'll create a sample module that we'd like to use in our application. Let's create a file called sample.js in the src/app directory and add the following content in it:
    define(function (require) {
    return function () {
       console.log('Sample Module');
    }
    });
  4. Lastly, we'll need a file that will contain the main entry point for our application, and also makes use of our sample module. Let's create a file called main.js in the src/app directory and add the following content in it:
    require(['sample'], function (sample) {
    sample();
    });
  5. Now that we've got all the necessary files required for our sample application, we can setup a requirejs task that will bundle it all into one file:
    requirejs: {
    app: {
       options: {
         mainConfigFile: 'src/config.js',
         name: 'main',
         out: 'www/js/app.js'
       }
    }
    }

    The mainConfigFile option points out the configuration file that will determine the behavior of RequireJS.

    The name option indicates the name of the module that contains the application entry point. In the case of this example, our application entry point is contained in the app/main.js file, and app is the base directory of our application in the src/config.js file. This translates the app/main.js filename into the main module name.

    The out option is used to indicate the file that should receive the result of the bundled application.

  6. We can now run the task using the grunt requirejs command, which should produce output similar to the following:
    Running "requirejs:app" (requirejs) task
  7. We should now have a file named app.js in the www/js directory that contains our entire sample application.

There's more...

The requirejs task provides us with all the underlying options provided by the RequireJS tool. We'll look at how to use these exposed options and generate a source map.

Using RequireJS optimizer options

The RequireJS optimizer is quite an intricate tool, and therefore, provides a large number of options to tweak its behavior. The contrib-requirejs plugin allows us to easily set any of these options by just specifying them as options of the plugin itself.

A list of all the available configuration options for the RequireJS build system can be found in the example configuration file at the following URL:

https://github.com/jrburke/r.js/blob/master/build/example.build.js

The following example indicates that the UglifyJS2 optimizer should be used instead of the default UglifyJS optimizer by using the optimize option:

requirejs: {
app: {
   options: {
     mainConfigFile: 'src/config.js',
     name: 'main',
     out: 'www/js/app.js',
     optimize: 'uglify2'
   }
}
}

Generating a source map

When the source code is bundled into one file, it becomes somewhat harder to debug, as you now have to trawl through miles of code to get to the point you're actually interested in.

A source map can help us with this issue by relating the resulting bundled file to the modularized structure it is derived from. Simply put, with a source map, our debugger will display the separate files we had before, even though we're actually using the bundled file.

The following example makes use of the generateSourceMap option to indicate that we'd like to generate a source map along with the resulting file:

requirejs: {
app: {
   options: {
     mainConfigFile: 'src/config.js',
     name: 'main',
     out: 'www/js/app.js',
     optimize: 'uglify2',
     preserveLicenseComments: false,
     generateSourceMaps: true
   }
}
}

In order to use the generateSourceMap option, we have to indicate that UglifyJS2 is to be used for optimization, by setting the optimize option to uglify2, and that license comments should not be preserved, by setting the preserveLicenseComments option to false.

Summary

This article covers the optimization of images, minifying of CSS, ensuring the quality of our JavaScript code, compressing it, and packaging it all together into one source file.

Resources for Article:


Further resources on this subject: