As I have promised in this post, I am giving a review of the ADVANCED_OPTIMIZATIONS option in Google Closure JavaScript Compiler.
Beyond simply shortening variable names, Closure Compiler with ADVANCED_OPTIMIZATIONS, does three other important steps:
- aggresive renaming – not only renaming local variables and functions, but it renames GLOBAL variables and functions. In this way, it can ruin your public API
- dead code removal – it removes functions you are not using and segments of unreachable code. This can be fine for some apps, but it is definitely risky for JavaScript libraries, that expose some functions which are supposed to be called only by client code.
- function inlining – inserting the function’s body instead of the function call, where appropriate
So it is true that without some additional work, the ADVANCED_OPTIMIZATIONS option will just ruin your code and your public API. Of course the solutions are at hand, but the question is if they worth the effort.
Keep your public API
If you provide ONLY the code below to Google Compiler, it produces empty output:
function hello(name){
alert("Hello " + name);
}
What? Empty output? Well… yes, as you never call your function. Instead, for the next code:
function hello(name){
alert("Hello " + name);
}
hello('jslog');
it produces the following output:
alert("Hello jslog");
This is smart! But we want to preserve our API (by the way, in the tutorial for Google Closure Compiler Advanced Optimizations, Google says on this page that the hello function is preserved, while it is NOT – see section Removal of code you want to keep and try the code online at Closure Compiler UI Tool)
So if the hello method above would be part of the public API, it would break third parties using it. Google proposes a solution for this: export the public objects/functions into the global namespace using the window object:
function hello(name){
alert("Hello " + name);
}
hello('jslog');
window['hello'] = hello;
//and the output is:
function a(b){alert("Hello "+b)}a("jslog");window.hello=a;
//so the hello function is kept as a property on the global window object
Instead, if you use:
window.hello = hello;
you get
function b(c){alert("Hello "+c)}b("jslog");window.a=b;
which is surely not what you want. So make sure you use the window['public_name'] notation. You should also standardize the way you access properties in your objects, either using the array notation, or the dotted notation, otherwise the compiler could be mislead by a mix of the two. But sometimes we just need to use both, as properties may be automatically generated at runtime.
Other problems with the Google Closure Compiler ADVANCED_OPTIMIZATIONS are separately compiling blocks of code with dependencies to external JavaScript. The solution for this is
- using either exports like the above or with the
goog.exportSymbol()or - using extern files specifically provided as a compilation option
In any case, I think this is just a bit too clumsy.
Moreover, having a class and export all its properties/functions is quite a job to to if your app is already a large one. Just have a short example:
MyClass = function(name) {
this.myName = name;
};
MyClass.prototype.myMethod = function() {
alert(this.myName);
};
window['MyClass'] = MyClass; // <-- Constructor
MyClass.prototype['myMethod'] = MyClass.prototype.myMethod; <-- export mechanism
//the above compiles to
MyClass=function(a){this.b=a};MyClass.prototype.a=function(){alert(this.b)};window.MyClass=MyClass;MyClass.prototype.myMethod=MyClass.prototype.a;
Conclusions
After this short overview of the ADVANCED_OPTIMIZATIONS flag, I really think most people won't need it. If you already have a large library, having it compiled with advanced optimizations would be a total nightmare, as it would require a review of all public methods and properties and additional work for each. And the gain? Just a few kilobytes. I have tried compiling ExtJS Core with advanced optimizations and got aprox 62 KB, while with simple optimizations it is 74 KB. Not very well for the amount of effort it would require, in my opinion.
But if you still think advanced optimizations is for you, you are probably wanting to optimize a lot, and you should first start seaching for other ways to optimize - first, make sure you combine all your js code into one file. It's better to have one js file of 100KB rather than have 10 files each of 5 KB. So make sure you are doing every other possible optimization before moving to the advanced optimizations flag.
After all, it's up to you to decide if it's worth the effort!
PS: You can follow me on twitter @extjslog.
[...] The simple compilation option was used with Google Closure as this is typically the one that will be used. For a discussion on why, check out the excellent post on A Log of Javascript. [...]
Hello,
I am wondering the JavaScript obfuscation done by the Closure compiler and the Gpoogt Web Toolkit Java-JavaScript compiler. The GWT compiler can obfuscat ehte code. I would like to know in what way the GWT compiler is different
from the Closure?
Can I just give Javasciript code only ot the GWT compiler and get it JS Obfuscted?
In the Avanced Optiomization case,
we can list all the class names, method names and global variables that should not be substituted by the compiler
along with Javascript reserved words.
The local variables and local method names can be substituted. One has to make sure that these mehto names are not imported into other .js files suing “…src=” xyx.js”… for example.
The html consutrctions like “” the id and class values whcih are string literals should not be substituted if we include .css and .jsp files.
Any input and use of GWT compiler will be apprecaited!
Thanks
GL