Google’s closure compiler is an impressive tool that parses JavaScript code and make various optimizations on it, including minimizing its size.
This post will provide what is needed to effectively utilize it in minimum time.
Step 1 – verify consistant property access methods in your code ∞
The first thing you should do is make sure you have a consistent way of accessing object properties in your code – i.e don’t have one place in the code setting a property of some object, for example like this:
obj["hello"]="there"
or
return { "hello":"there" }
while in another place in your code you access it via the dot notation, e.g:
myobj = obj.hello
The reason this will cause problems is because the closure compiler will not rename strings but will rename the access fields in the dotted notation – which will of course cause problems in this case.
Step 2 – list the files that can be clumped together in one compilation ∞
The more files that can be compiled together with Google Closure compiler, the less you will have to deal with defining external functions and variables (i.e, those that are used by the compiled code but are defined in external/uncompiled code) or exporting variables and functions (those that you don’t want the compiler to rename since they are used by external/non-compiled code.
Step 3 – list internal functions and variables that non-compiled code needs to access ∞
Go through your code and list the functions and variables that you don’t want to be renamed by the Closure compiler since they have to be accessed by Javascript code that will not be compiled (You also need this if you have strings in the compiled code that are evaluated at runtime as function calls since strings are not changed by the compiler).
So, for example, say you have the following in the code you want to compile:
document.mydiv.innerHTML="<a href='#' onClick='myFunc1()'>Click</a>";
function myFunc1()
{
alert("link was clicked");
}
function myFunc2()
{
alert( "my API function was called" );
}
You will need to export MyFunc1 (because it is called from within a string) and MyFunc2 (because it is called from outside the compiled code).
The way to export functions so that they can be accessed after they are renamed by the compiler is to do the following trick – just add to your code:
window["myFunc1"]=myFunc1;
window["myFunc2"]=myFunc2;
window["myObj"]={};
window["myObj"][myMethod"] = myObj.myMethod;
This way, the compiler will rename myFunc1 and myFunc2 in the optimized code (and also myObj.myMethod), but the outside code will still be able to access them by their original name.
Step 4 – list external functions and variables that compiled code needs to access ∞
You need to let the closure compiler know which function calls and variables should not be renamed since the original name is needed to be able to call the external function/variable.
For example if you need to access an external variable named g_mymap and an external function named myinit then create a file named externs1.js
for example which contains the following:
var g_mymap;
function init( str ) {}
Step5 – Compile! ∞
java -jar compiler.jar --compilation_level ADVANCED_OPTIMIZATIONS
--js=../src/script1.js
--js=../src/script2.js
--js=../src/script3.js
--js=../src/script4.js
--externs ../src/externs1.js
--js_output_file=../release/code.js
Note that in the above example script1.js
to script4.js
are the scripts who’s variables and functions will be renamed in the optimization process, externs1.js
contains the list of external functions and variables that you wish to access from within the compiled code (and thus you don’t want to be renamed – see step 4) and code.js
will be the minimized and optimized code produced by the Google Closure compiler.