I've been checking out the Google Closure Compiler recently. I downloaded the .jar file and gave it a test drive. So far, I must say that I've been very impressed. I can certainly see its usefulness beyond minimization. Props to the Google team!
I do have one small gripe though. It seems to me that you only get two options as far as optimization goes. It's either SIMPLE_OPTIMIZATIONS or ADVANCED_OPTIMIZATIONS. The former, although adequate, is very simple IMHO. For one thing, unless I'm missing something, it leaves all property names untouched. It also does not remove unreachable code. On the other hand, the latter option is simply too destructive.
Now, I'm fairly new to JavaScript, so it's very probable that I'm missing something. If I say something stupid, feel free to school me. That said, I can understand the issues with renaming in JavaScript. The Google team recommends using the bracket notation (object['property']) instead of the dot notation (object.property) to access the properties that you do not want changed and never mixing the two uses. They also suggest 'exporting' methods by using the following pattern:
MyClass = function(name) {
this.myName = name;
};
MyClass.prototype.myMethod = function() {
alert(this.myName);
};
window['MyClass'] = MyClass; // <-- Constructor
MyClass.prototype['myMethod'] = MyClass.prototype.myMethod;
However, there are legitimate cases that you want to mix the two notations. Let's say we are building a game. The game's code is completely isolated inside a closure. It does not 'export' anything to the global scope, nor does it need to. In fact, it really should not touch the window object. However, it does need to read some in-game properties from XML configuration files.
Sample JavaScript:
var TheGreatAdventure = (function(window) {
function Fighter() {
// Private to application
this.id = 42;
// Accessible to XML configuration system
this.name = 'Generic Jen';
this.hitPoints = 100;
this.onAttack = genericFighterAttack;
this.onSpeak = genericFighterSpeak;
...
}
Fighter.publishedProperties = ['name', 'hitPoints', 'onAttack', 'onSpeak']
function genericFighterAttack() {...}
function genericFighterSpeak() {...}
function cassieAttack() {...}
function cassieSpeak() {...}
...
EntityReader = {
...
function readFromXMLNode(attributes, entityClass, entityInstance) {
for (var i = 0; i < attributes.length; i++) {
var attribute = attributes[i];
if (attribute.nodeName in entityClass.publishedProperties)
entityInstance[attribute.nodeName] = bindContext[attribute.value];
}
}
...
}
}(window));
Sample XML configuration file:
<Fighter name='Custom Cassie' onAttack='cassieAttack' onSpeak='cassieSpeak'/>
Not only would the above system fail to assign the properties, the functions cassieAttack and cassieSpeak would have been eliminated during minimization as dead code!
Now, there's no way I'm accessing all of the 'published' properties using the bracket notation throughout the game's code. Even if there's no run-time penalty in doing so (there should not be any), there's still a lot of extra typing involved and it's (IMO) an eyesore. With such common properties, everything would show up as a string inside a text editor, defeating the purpose of syntax highlighting!
It seems to me that a simple @preserve (or something similar) directive over those properties would allow ADVANCED_OPTIMIZATIONS to be used with minimum cost in final program size. Am I missing something?