Using Google's Closure to Compile and Verify your JavaScript

Contents

A large application is nearly guaranteed to come with an equally large amount of JavaScript attached to it. During development it makes sense to divide the JavaScript of the application into multiple sensibly named files both to make finding specific functionality in the code base easier, and to keep the file length to a reasonable size for readability/comprehension purposes. More importantly though, this allows you to build modular, reusable components by separating functionality and sharing common methods within the application.

However, when it comes time to move your site to the production environment, this development processes' inefficiencies become noticeable in slow loading pages. The most obvious pitfall is the fact that having multiple different files means that new HTTP requests have to be issued for each file, bringing with it an additional round trip time. Combined that with the fact that HTTP specifications limit the browser to downloading no more than two files simultaneously from the same domain, and you'll see even slower page loads. There are ways to mitigate this somewhat; for example by serving your static media from different domains to allows for better parallel downloading. In addition to these issues, most browsers prevent the rest of the page from being loaded while a JavaScript file is being downloaded and parsed. The effect of this is often seen in pages that don't appear to load for an extended time, and then suddenly appear in their finished state. This is bad for the user experience as it leaves a significant amount of time where the user can not tell that anything is actually happening; making the page load appear to take longer than it actually does.

One way that these problems can be mitigated by combining all the multiple JavaScript files into a single compiled file. This will reduce all of the multiple HTTP request round trips to a single one, as well as compress the code into a much smaller version.

Introducing Google Closure

The Google Closure Compiler is a tool designed to solve these problems. It will take care of automatically merging all your different JavaScript files in to one master file, as well as provide some other significant speed and sanity benefits. For example, not only does the Closure Compiler combine multiple source files, but it will also parse and analyze it to remove dead code and rewrite and minimize the rest (by striping out comments, and compressing variable and function names). Additionally it will verify syntax, variable references and types, as well as providing warnings when it finds common JavaScript pitfalls.

How to Get it

Sounds great right? Lets get cracking! Firstly we need to go download the Compiler from the Google Developers Site; scroll down to the bottom of the page and click the 'Download the application' link. I'm going to set-up the compiler in /opt on my server. You can do the same:

sudo mkdir /opt/closure cd /opt/closure sudo unzip path/to/compiler-latest.zip sudo chmod a+r *

That's all there is to it! You should be able to run the command below now as a regular user:

java -jar /opt/closure/compiler.jar --help

How to Use it

Actually using the compiler is quite simple as well. Simply cd into the directory that holds your JavaScript files for your application and run the compiler with the argument '*.js' for it to process all the JavaScript files in that directory. That's only slightly helpful though, as often times the files will have to be sourced in a particular order before they can be run client side due to shared dependencies. To enforce the order that the scripts are merged in you use the --js parameter on the compiler, so that the command now looks like this:

java -jar /opt/closure/compiler.jar --js script1.js --js script2.js --js script3.js

The first thing that you'll notice (if you don't have any errors in your code) is that the output of the compiled JavaScript is sent directly to the screen; that's not that helpful. We want to send that to a file for our application to use:

java -jar /opt/closure/compiler.jar --js script1.js --js script2.js --js script3.js --js_output_file scripts-compiled.js

Finding Errors

If you got some errors when you ran the compiler, then you've already seen another massive benefit that the Closure Compiler provides: detailed error information. The compiler will output the file and line of any errors that it encounters as it processes your files, as well as a helpful message on how to fix them. Not only does it notify you of syntax errors, but it will also tell you of any common issues that are present.

My personal favourite - something that has cost me quite a lot of time trying to figure out in the past - is that the Closure Compiler will throw an error on trailing commas in arrays. This is something that I've noticed many developers tend forget about. An example of the problem in action would be this array:

var arr = [1,2,3,];

This will cause you no problems at all until you attempt to load the page in Internet Explorer 8 or less. At that point you'll find an error about an Expected identifier. There are many other issues in your code that the Closure Compiler will detect and inform you of. Some of the examples that I've run into are:

If you have JSDoc style annotations in a comment, but forgot to start the comment block correctly

If you use reserved words as a variable or function; eg. var.class or var.delete()

Integrating the Closure Compiler in your Build Process

Now that we know how to create our compiled version of our code base it's time to start using it. We don't want to be using the compiled version during development, as we then lose the fidelity gained by having multiple files when debugging (also full variable names and accurate line numbers), additionally you would have to recompile your scripts whenever you make a change. So we need to have a configuration setting to toggle the use of the compiled scripts inside our application:

# in your config.php file define('PRODUCTION', <is_this_production:true|false>); # in your application require_once 'config.php'; if (PRODUCTION) { echo '<script type="text/javascript" src="js/scripts-compiled.js"></script>'; } else { echo '<script type="text/javascript" src="js/script1.js"></script>'; echo '<script type="text/javascript" src="js/script2.js"></script>'; echo '<script type="text/javascript" src="js/script3.js"></script>'; }

There's no point in keeping the scripts-compiled.js file on your development copy at all, since you're never going to be using it. Additionally, you don't want to have to make sure you've re-compiled and committed the output whenever you wish to push to production. To fix this, we're going to add a step in our build process that will take care of compiling the most recent version of your JavaScript each time a new build is run. To do this in Jenkins, simply add a new Execute shell step at the beginning of your build process that looks like this:

cd <workspace>/js java -jar /opt/closure/compiler.jar --js script1.js --js script2.js --js script3.js --js_output_file scripts-compiled.js

That's all there is to it! If there are any errors generated by the Closure Compiler the build will fail, preventing potentially broken code from reaching production.

Results Seen

I implemented this process in my current project and am seeing significant improvement in page load times. Before doing this the application was divided into 25 different JavaScript files (not including jQuery, jQuery plugins, and other third party libraries), with a total line count of over 11,000 and a combined file size of 400K. After performing the compilation, I now have one single JavaScript file, whose line count is a mere 288 lines and file size is only 128K. This resulted in an average of 1.5 seconds decrease in page load time - quite a significant difference!

Have Something to Say?

Questions? Comments? Concerns? Let me know what you’re thinking.