Grunt in Action

If you know JavaScript you ought to know Grunt – the Task Runner for managing sophisticated web applications. From a basic understanding to constructing your own advanced Grunt tasks, this tutorial has it all covered.

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

Step 4 – optimizing our build files

At this point, we should have a structured set of source files and can now perform additional transformations on the result. Let's start by downloading the plugins from npm and saving them in our package.json file:

$ npm install --save-dev grunt-contrib-uglify grunt-contrib-cssmin
grunt-contrib-htmlmin

Then, at the top of our Gruntfile.js file, where we have loaded our other Grunt plugins, we will load our new additions with:

grunt.loadNpmTasks("grunt-contrib-uglify"); grunt.loadNpmTasks("grunt-contrib-cssmin"); grunt.loadNpmTasks("grunt-contrib-htmlmin");

Scripts

We will start by compressing our scripts. In this example, we use the grunt-contrib-uglify plugin http://gswg.io#grunt-contrib-uglify), which is a wrapper around the popular UglifyJS library (http://gswg.io#uglifyjs). Now we have loaded the plugin, which provides the uglify task, we just need to configure it:

uglify: { compress: { src: "<%= coffee.build.dest %>", dest: "<%= coffee.build.dest %>" } }

Here, inside the uglify property, we have made a compress target, which has src and dest set to the same file. Instead of entering the actual filename, we are making use of Grunt templates to retrieve the value at the given configuration path (coffee.build.dest), which in this case, resolves to build/js/app.js. Grunt templates make it easy to have a single source of truth within our configuration. Therefore, if we ever want to change the file path of our JavaScript, we only need to change one configuration entry.

Since we have set the source and destination to the same file path, in effect, we are overwriting our JavaScript with the compressed version of itself. However, if we were writing a JavaScript library instead of a web application, we'd most likely want to compress our app.js file into an app.min.js file, so its users could download an uncompressed and a compressed version.

Running this uglify task with this basic configuration should result in the following app.js file:

(function(){var a,b;a=function(a,b){return a+b},b=function(a,b)
{return a-b},alert(a(7,b(4,1)))}).call(this);

Generally, this will suffice, however, UglifyJS also offers advanced features. For example, in some cases, we might have portions of code that are only used during development. We could remove this unnecessary code with the following technique. By defining a DEBUG variable and place our debug-related code inside an if block as follows:

if(DEBUG) { //do things here }

Then, if we used the following options object inside our uglify configuration as follows:

options: { compress: { global_defs: { "DEBUG": false }, dead_code: true } }

This would result in UglifyJS locking the value of DEBUG to false and also to remove the inaccessible code (dead code). Therefore, in addition to compressing code, we also have the ability to completely remove code from our builds. The documentation for this feature can be found at http://gswg.io#grunt-contrib-uglify-conditional-compilation.

Styles

To compress our styles, we use the grunt-contrib-cssmin plugin (http://gswg.io#grunt-contrib-cssmin), which is a wrapper around the clean-css library (http://gswg.io#clean-css). Since we have installed this plugin, we just need to include the cssmin task configuration:

cssmin: { compress: { src: "<%= stylus.build.dest %>", dest: "<%= stylus.build.dest %>" } }

Similar to our scripts configuration, we can see that the only real difference is that we point to the stylus task's output instead of pointing to the coffee task's output. When we run grunt cssmin, our css/app.css file should be modified to the following one:

html,body{margin:0;padding:0}.content .middle{font-size:16pt}@media
(max-width:768px){.content .middle{font-size:8pt}}

Views

Finally, to compress our views, we will use the grunt-contrib-htmlmin plugin (http://gswg.io#grunt-contrib-htmlmin), which is a wrapper around the html-minifier library (http://gswg.io#html-minifier). The htmlmin configuration has a little more to it: since its compression options are disabled by default, we need to enable the rules we wish to use:

htmlmin: { options: { removeComments: true, collapseWhitespace: true, collapseBooleanAttributes: true, removeAttributeQuotes: true, removeRedundantAttributes: true, removeOptionalTags: true }, compress: { src: "<%= jade.build.dest %>", dest: "<%= jade.build.dest %>" } }

Now our htmlmin task is configured, we can run it with grunt htmlmin, which should modify our build/app.html to the following:

<!DOCTYPE html><html><head><link rel=stylesheet href=css/app. css><body><section class=header>this is the <b>amazing</b> header section</section><section class=content><div class=top>some content with this on top</div><div class=middle>and this in the middle</ div><div class=bottom>and this on the bottom</div></section><section class=footer>and this is the footer, with an awesome copyright symbol with the year next to it - © 2013</section><script src = js/app. js></script>

In addition to the GitHub repository, we can read more about html-minifier on Juriy "Kangax" Zaytsev's blog at http://gswg.io#experimenting-with-html-minifier.

Summary

In this article we performed additional transformations on set of source files by using Grunt.

Resources for Article:


Further resources on this subject:


Books to Consider

comments powered by Disqus