ShiftEleven

Aliases with Google Closure

I'm starting to use the closure library and all of it. The closure compiler is nice because it can compress your JS code down, a LOT. In order to get the biggest bang for your buck. you want to use the advanced optimization settings. It can eliminate unused code, inline functions, and rename variables.

In order for variable renaming to work, you have to behave by closure's rules. One rule closure has is: Let me do the optimization. One of the main reasons for this is that some shortcuts can make it hard to determine your intent.

One shortcut I like to use is to create alias to JavaScript objects that have long names or long namespaces.

(function() {
  var alias = a.very.long.namespace;
  /** @constructor */
  alias.NewClass = function() {};
})();

Now, to you are I, we can easily tell that I intend to use this self-calling anonymous function as a closure to store my alias; however, how can a compiler know that this was my intent.

Intent is a key concept when you work with the advanced compilation. In the above example, Closure knows that a.very.long.namespace.NewClass is even a class because of the constructor annotation. The way to tell Closure that you intend to make aliases is by using the goog.scope function1.

goog.require('goog.dom');
goog.require('goog.events');
goog.require('goog.events.EventType');

goog.scope(function() {
  var dom = goog.dom;
  var events = goog.events;
  var EventType = goog.events.EventType;

  events.addEventListener(
      dom.getElement('myElement'),
      EventType.CLICK,
      function() { alert('I was clicked'); });
});

Behind the Scenes

So what does Closure do with this info? Well, if your code is not compiled, nothing :) The implementation of goog.scope will just call the function that was passed in as an argument. Now if you took the time to even investigate aliasing, then you probably care about what happens when you run the code through the compiler.

The compiler will actually expand all of your aliased variables into their fully qualified path in one of the compiler passes through the code before sending it to other passes. Think of it as a preprocessing step.

Caveats

Since goog.scope is a special function, you should know that it has special rules that you need to follow. They are pretty easy and you probably won't run into them unless you're doing something sneaky.

Conclusion

To get the biggest bang for your buck out of the Closure compiler, you sometimes need to give it hints about what you intend to do. goog.scope is just one of those ways that you can provide it with some extra context so that it can do its job better. This extra bit of metadata can also help you do your job better too because the Closure compiler will be able to message you about errors when it sees a mismatch between what you intend to be doing, and what you're actually doing.

If you would like to read more about the goog.scope proposal and action plan, check out the implementation document. It also outlines other options considered for solving the aliasing problem and why they were less ideal. Also, feel free to investigate the compiler source code for goog.scope.

Footnotes

  1. Yes, I know that you can do this with jQuery simply as $('#myElement').click(function() { alert(...); }); :p

Comments

comments powered by Disqus