JavaScript Concatenation and Minification with the Grunt.js Task Runer

Node.js

Grunt.js LogoCombine multiple JS files into one using JavaScript, Node.js and Grunt.

In the article: “Getting Started with Grunt: The JavaScript Task Runner,” we covered the bare-bones basics of how to set up and use Grunt, to automate and manage your JavaScript build task. In that article, we used a Grunt plugin called “grunt-contrib-uglify” to minify and obfuscate our JS code. But while minification is a common task for any build system, file concatenation is also a technique used to minimize the number of http requests. This helps to improve web page performance. In this article, we will look at the Grunt plugin: grunt-contrib-concat. It exposes a number of very useful methods for simple, to advanced file concatenation.

Example # 1

In Example # 1, we have the contents of “package.json“. Naturally, Grunt is listed as a dependency, but there is a reference to the “grunt-contrib-concat” plugin as well.

The Project File Structure – And Files to be Concatenated

 

The Empty Distribution Folder
The Empty Distribution Folder

 

 

Example # 2

In Example # 2, we have the JavaScript code that will set up and run the Grunt tasks. There are two sections to this code: the call to the grunt.initConfig() method, and the two commands that load the plugin and register the task.

Grunt Init configuration

The method: initConfig belongs to the grunt object. For this article, we are concatenating three JavaScript files. As you can see, the sole property to the object-literal passed to the initConfig method is concat. Its value is another object with two properties: “options” and “dist“. The “dist” property provides an object with critical details for this operation: the location of the source files (“src“). It also provides the location of the file to be created that contains all of the source files (“dist“). Note that the value of the “src” property is an array. This ensures that any number of files can be specified. The path is relative to the Gruntfile. In this example, the “options” property specifies the string that will be used to separate each concatenated file.

Loading the Grunt Plugin and Registering the task

Under the call to the grunt.initConfig() method, we load the “grunt-contrib-concat” plugin by passing it as a string to the grunt.loadNpmTasks method. This makes the plugin available to the rest of our code. Next, we register the “default” task with a call to the grunt.registerTask() method. The first argument is the name of the task (in this case it is “default“). The second argument is an array containing one or more named tasks.

That is all we need to run our tasks. So now, in the terminal, we simply type: “grunt“. After grunt has completed running, you should see a new file in the “dist” folder named: “allScripts.js.

The Built File
The Built File

Summary

In this article, we talked about JavaScript minification using Grunt. We discussed configuring the project dependencies in the file: package.json, which is needed in order for our application to work properly. We also reviewed the file: Gruntfile.js, which is where we did set configuration properties for the build, and then run the tasks. There is plenty to dive into on the subject of minification with Grunt. This article provided the most basic elements of how to set, configure and run a task that combines multiple JavaScript files into one.

Helpful Links for: Grunt.js file concatenation

http://stackoverflow.com/questions/16377674/using-grunt-to-concatenate-all-vendor-javascript-files

https://github.com/gruntjs/grunt-contrib-concat

http://stackoverflow.com/questions/12722855/using-grunt-concat-how-would-i-automate-the-concatenation-of-the-same-file-to-m

Getting Started with Grunt: The JavaScript Task Runner

Node.js

Grunt.js LogoAutomate and manage your JavaScript build tasks with JavaScript, Node.js and Grunt.

Today, even the most straightforward web-based application will involve JavaScript, and chances are that JS code will not be too simple. In-fact, it is often inevitable that your JavaScript could start to grow over time and / or span multiple files. When these dynamics are in-play you’ll find yourself spending more and more time having to organize and test your code. Regardless of the details, this kind of maintenance quickly becomes tedious. I think many will agree that when humans have to perform repetitive / tedious tasks, the chance of error increases. Fortunately, this is the exact kind of work that a computer is thrilled to do, and do well. Using a built tool to manage your JavaScript build tasks is not only efficient, but also a smart way to go.

Grunt is promoted as a “Task Runner.” Semantics aside, it is an aptly named tool that provides a significant level of flexibility and power, when it comes to managing and automating your build tasks.

In this article, I will intentionally “scratch the surface.” While there is a great deal of depth to Grunt, getting started is a critical first step. My focus here is to provide you with information that simply enables you to set the minimum configuration required for your first (albeit simple) automated task with Grunt.

Prerequisites

In order to use Grunt, you’ll need Node.js and the The Grunt CLI (Command-Line Interface). Installing Node is beyond the scope of this article. If you have not installed Node yet, you can start here: http://nodejs.org/

The Grunt Command-Line Interface

The Grunt CLI is used to launch Grunt. While this may sound a bit confusing, installing the Grunt CLI does not actually install the Grunt task runner. The CLI is used to launch whatever version of Grunt is defined in your package.json file (more on that file later). The advantage of this is that your projects can all use different versions of Grunt without concern for conflicts. The CLI does not care, it simply launches whatever version your project uses.

(You might need to use the sudo command when executing npm install, depending on your account priviliges.)

Note that in the example above the “-g” flag is used. This is recommended. It installs the module globally so that it can be executed from any folder on your machine, and need not ever be installed again.

package.json

Once you have installed the grunt-cli globally, you can put your project together. The first step is to create a package.json file. The package.json file is a feature of node.js. You can learn more about it here: https://npmjs.org/doc/json.html

In this example, we have named this project: “Grunt-Test-1”, and given it a version #. Both of these values are arbitrary, and completely up to you. But keep in mind that the “name” property is potentially used by Grunt in some cases, so choose a name that makes sense. The “devDependencies” property is an object that whos whose keys contain node modules that your project depends on. The value for each key is the exact (or minimum) version number required for that module.

The Project File Structure

Image # 1: The project’s file structure

Once your package.json file is ready, simply run the following command: “npm install”. Node will refer to your package.json file in order to understand what it needs to install so that your project works correctly. Keep in mind that the “installation” is simply a download that is local to this folder. Its is not “installed” on your computer, like a native / compiled application.

Example # 1

For this example, we have only two dependencies: grunt, and grunt-contrib-uglify. The “grunt” requirement is critical because we want to use Grunt. Everything else is optional. But if grunt is the only dependency, then there won’t be too much we can do. Grunt plugins allow us to define tasks that can be managed by Grunt. The “grunt-contrib-uglify” plugin provides JavaScript minification and obfuscation. For this article, we will simply minify a JavaScript file and save it with a new name.

Once you have created your package.json file, you can install all required modules with two easy words: “npm install”. Entering that command in your terminal will allow you to leverage the Node Package Manager, otherwise known as: “npm” (make sure you are in the root folder of your project). The Node Package Manager will look for a file named package.json in the current folder, and read the devDependencies object. For each property of the “devDependencies” object, npm will download whatever file is specified by the version # you have provided as a value for that property.

One of the ways in which this approach is so helpful is that it negates the need to commit large files to your version control. Node modules are often a combination of text files (e.g. “.js”, “package.json”, “README”, “Rakefile”, etc.) and executables. Sometimes a combination of just a few dependencies can add several megabytes to your project, if not more. Adding this kind of weight to your code repository not only eats up disk space, but it is somewhat unintuitive because version control systems are really meant to store and manage text files that you (or your teammates) will change over time. Node.js modules are managed by the contributors of those modules, and you probably won’t need (or want) to change their source code. So, as long as your project contains the package.json file, whenever you (or anyone on your team) check out that repo, you can run “npm install” to the exact versions of the modules you need.

The Gruntfile

The Gruntfile is the JavaScript code you create to leverage the power of Grunt. Grunt always looks for a file named: “Gruntfile.js” in the root of your project. If this file does not exist, then all bets are off.

Inside of Gruntfile.js, all of your code will be wrapped in one function: module.exports.

Example # 2

In Example # 2, we have defined the “exports” method of the “module” object. Right now it does nothing, but all of your grunt code will go inside of this function.

Example # 3

In Example # 3, we make a call to the grunt.initConfig method. This method takes an object as its sole argument. In this object, we set properties that provide the details Grunt needs in order to work the way we want. Here we set one property: “pkg”. In order to set the value for that property, we tell grunt to read the contents of our “package.json” file. The main reason for this is that we can use the metadata that is stored in package.json, and use it in our tasks. The two delimiters: <% %> can be used to reference any configuration properties. For example: <%= pkg.name %> would display the name that you have given your project. In this case it is: “Grunt-Test-1”, but we could also access the version number of our project in this manner: <%= pkg.version %>.

Since we will be using the “grunt-contrib-uglify” plugin, lets update Gruntfile.js so that it is configured to leverage this plugin.

The Empty Build Folder
The Empty Build Folder

Image # 2: The empty build folder

Example # 4:

In Example # 4, we have added a new property to the config object: “uglify”, which provides the detail that the “grunt-contrib-uglify” plugin needs. This property is an object which, in-turn, has two properties that are objects. As the name suggests, the “options” property contains options for the “grunt-contrib-uglify” plugin. The “build” property is an object that provides two properties that are critical to the “grunt-contrib-uglify” plugin:

  • src: The location of the file to “uglify”
  • dest: The location where the “uglified” file will be placed

While we have provided some important details, running Grunt at this point will produce no results because there are no tasks specified. Let’s take care of that next:

Example # 5:

In Example # 5, we have made two changes: We load the “grunt-contrib-uglify” plugin, and then we register the default task, which in this case is: “uglify”. Notice that the “uglify” task is passed to the registerTask() method, as the sole element of an array. This array can contain as many tasks as you like, always represented as a string. The purpose of the “default” task is to let Grunt know that outside of any other named tasks that are registered, this is the list of tasks that should be executed.

Now that we have provided the minimum details needed, we can run Grunt by simply typing “grunt” in the terminal. Once Grunt completes, you should see a new file in the “build” folder that is in the root of your project. That file should be named as per the details provided in the “uglify” section of the object passed to the grunt.initConfig() method. You’ll see that file has been “uglified,” meaning that it has been minified and obfuscated. The end result should be a significant reduction in file size.

The Built File
The Built File

Image # 3: The  built file

Summary

The example used in this article was very basic (about as basic as you can get!). My goal was to provide the critical base information needed in order to understand, setup and use Grunt for the first time. There is a great deal of power available from Grunt. While it may not fit everyone’s needs, it can, in many cases, provide a robust and actively maintained open-source framework with which to create simple or complex build processes.

Helpful Links for Getting Started with Grunt

http://gruntjs.com/

http://gruntjs.com/getting-started

http://net.tutsplus.com/tutorials/javascript-ajax/meeting-grunt-the-build-tool-for-javascript/

http://blog.mattbailey.co/post/45519082789/a-beginners-guide-to-grunt