Using grunt to combine and minify your javascript files

A beginner's guide to implementing grunt for front end developers

grunt,node,minify,uglify

06/16/2013

I recently had a little trouble getting up and running with Grunt, so I figured I'd post my process. I feel like once you've got the system going, adding different tasks is easy - and super useful.

The first issue I had was that I'd had an old version of grunt installed on my machine. If that's the case for you, you need to make sure grunt is moved from wherever you installed it. You can do so with this command:

npm uninstall -g grunt

Then you can install the proper, most recent version of grunt with this:

npm install -g grunt-cli

Next you have to create a package.json file (touch package.json from the command line). This file tells node what modules grunt will be using in its tasks. I've read different opinions on how to build this initial file, including npm-init, but I found that a bit confusing, not to mention it involves specifying a lot of things that might not be applicable to you in your project. So I just use:


{
  "name": "Grunt-Test",
  "version": "0.0.1",
  "author": "Mike Heavers"
}

From there, you can add grunt by making sure you're in your project's directory in terminal, and running

npm install grunt --save-dev

That will add grunt to your dev dependencies in the package.json file if everything is installed properly, as well as create a node_modules folder with grunt inside.

Next you need to create your grunt file (touch Gruntfile.js) in the same directory as the package.json folder. This is the file that does all the work for Grunt. Its basic template would be this:


module.exports = function(grunt) {

  // Project configuration.
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
  });

};

All this does is make the connection to the package.json file, but we'll need to add tasks. An easy task to start with is uglify (minification of javascript files). If you're doing a standard web build, a starting file structure might be:


package.json
Gruntfile.js
node_modules/
html/
html/index.html
html/js/
html/css/

etc. To demonstrate, I'll start with two javascript files in the js folder, main.js and secondary.js, that I'll compile into one - site.min.js. You can put whatever you want in these javascript files, just make sure to put something in order to test it, like so:

$(document).ready(function(){
  var mainVar = 'main';
  console.log('main.js: ' + mainVar);
});

$(document).ready(function(){
  var secondaryVar = 'secondary';
  console.log('secondary.js: ' + secondaryVar);
});

Next, you'll need to install the uglify grunt module. I've seen suggestions to install the entire suite of grunt-contrib modules, but again, this seems overly complex, and for me it resulted in some errors. I find it's best to go module by module, so we'll just instill uglify. You can do so in the terminal with this:

npm install grunt-contrib-uglify --save-dev

You can find a list of all of the grunt contrib modules here. They have great documentation on their usage and configuration. Speaking of configuration, now that the module is installed, we need to configure it in the Gruntfile.js. Here's my setup:


module.exports = function(grunt) {

  // Project configuration.
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    uglify: {
      options: {
        mangle: true,
        wrap: true,
        banner: '/*! <%= pkg.name %> - v<%= pkg.version %> - ' +
        '<%= grunt.template.today("yyyy-mm-dd") %> */'
      },
      my_target: {
        files: {
          'html/js/site.min.js': ['html/js/main.js', 'html/js/secondary.js']
        }
      }
    }

  });

  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.registerTask('default', ['uglify']);

};

Within the uglify node of the JSON file, we specify its options - mangle will truncate its variable names (it's set to true by default, so we could really remove this), and wrap (which wraps the javascript in a closure to help avoid leakage). The banner option simply inserts a comment at the beginning of the minified javascript file with whatever content you choose. I've included it simply to show how variables can be inserted with grunt. This configuration simply renders:

/*! Grunt-Test - v0.0.1 - 2013-06-16 */

The target ("my_target") can be given a name of whatever you wish. You can have multiple targets as well, but here we only have one here. Within it, we're simply saying - combine the files main.js and secondary.js into one file, site.min.js. So in your html file you, would only need to include a script tag that references site.min.js:

<script src="js/site.min.js">

That's all there is to it. Now just run "grunt" from the terminal, and your javascript should be minified, mangled, wrapped with a closure and given a banner. Later we'll look at how to compile Sass, and how to watch a series of folders so that whenever they're changed, grunt automatically runs the appropriate tasks.