Compiling Minified Multi-File Javascript
Posted: 05 January 2012
I've been doing a lot of Javascript development lately. For most of 2011 I focused almost exclusively on Kinect device development in WPF, and I really missed the web after all that time on the desktop. Now that I'm getting back in to web development, I've been really curious about Javascript as a language.
While doing all this js development I quickly ran in to the issue of dealing with multiple js source files and combining them and minify-ing them into a single file. Most of what I've leanred about this process came from the audiolib.js project. Jussi Kalliokoski has put together some great structure on that project. However, I've found very few posts on this topic so I thought I'd write about it.
As we all know, a single minified .js file is
optimal for the web. I've been working with about five bulky .js files
and needed to shrink them down. Combining multiple source js files into a single file is trivial
with cat:
cat src/*.js > final.js
For my first dive into js minification, I've been using UglifyJS. Most folks out there seem to be using the YUI or Closure compressors, but I thought I'd give UglifyJS a shot. UglifyJS is actually built in Javascript and runs on node.js. This post on badassjs.com suggests that UglifyJS is the fastest and best js minifier out there, but I'll leave the performance and language wonks out there to be the judge of that.
Install UglifyJS:
npm install uglify-js
Running UgilifyJS is cake:
uglifyjs final.js > final.min.js
And poof, we've now combined and minified multiple js files into a single file!
Module Wrappers
Wait, there's a little more to the story. In my js development I've been working on a re-usable, extendable Javascript module. All of the objects in my js source files needed to be wrapped inside of a module. With a single file this is obviously easy. But how do you do this with multiple js source files?
var LLAMAMODULE = (function() {
var myLlama = {};
// content of multiple source files go here
// uhhhh, how do I do this?
return myLlama;
}());
The answer is to create starting and ending wrapper .js files
and include them in the right order when using cat:
// wrapper-start.js
var LLAMAMODULE = (function(){
var myLlama = {};
// wrapper-end.js
return myLlama;
}());
When you use cat, just make sure to place the wrappers
appropriately:
cat src/wrapper-start.js src/*.js src/wrapper-end.js > final.js
BAM, now you've got a single file with all your awesome stuff wrapped in to a module.
Putting it together with Make and a test page
Now how do you test your js code in a browser? I created a makefile so that I can compile my Javascript on demand:
all: lib/final.min.js
lib/final.js: src/wrap-start.js src/*.js src/wrap-end.js
mkdir lib/ -p
cat $^ > $@
%.min.js: %.js
uglifyjs $^ > $@
My js code now resides inside lib/, and I can reference
it from an HTML page (for testing, or for your real pages):
<html>
<head>
<script src="../lib/final.js"></script>
</head>
...
</html>
It should be obvious, but don't reference the minified js when doing tests or debugging. You'll be spending a lot of time banging your head against the wall trying to find those rows and columns and reconciling minified var names!
In summary:
- Use
catto combine multiple js files together - Use wrapper .js files for modules
- Use UglifyJS (or your favorite minifier) to minify your js
- Use a makefile (or another flavor of scripting) for concatenation and minification
- Don't reference the minified js when testing or debugging
Happy minify-ing!