DotNetWise©

Tuesday, November 17, 2009

Closure Compiler Externs Extractor

Many programmers are trying to use the Google Closure Compiler in their own applications but quickly they are hitting a wall: suddenly their third party APIs got renamed and the application doesn't work anymore, because they did not define the correct Externs!

If you already know what Externs are you can go directly to the Closure Compiler Externs Extractor example.

Closure compiler is an amazing tool if it is used as it was designed. The difference between it and other tools is that it really compiles the javascript and not just "minify" like YUI Compressor or Ajax Minifier does.

One of the concepts behind is that we can rename all the symbols and not just the local variables.
Nice to hear that, but this is very bad for the current javascript pieces of code that were not written with Closure Compiler's rules in mind.

i.e.

MyApp.MyNamespace.MyObject.MyMethod = function() {...}
var o = MyApp.MyNamespace.MyObject.MyMethod();
gets compiled into
b.c.d.e = function() {...}
var a = b.c.d.e();


Well that is very good if I own the source code of MyMethod, so it will also be renamed along the road to the same short name e.
However, if I would like to make this code available for other people to use into their application as a plugin - it might not be that good, as on every compilation I would get a different method name.
Google's solution is to export your symbols.
Yeah, I can do that, because it's my code, right?


MyApp.MyNamespace.MyObject.MyMethod =
window["MyApp"]["MyNamespace"]["MyObject"]["MyMethod"] = function() {...}


This would still compress my code on all the location where it is used (as above), but will also make it available of other users to use it with public friendly names.

Well, this is good, but is very bad if I need to use an external API that is maintained by a third party.
In that case Google's solutions is to use an Externs file on the compilation.

An externs file is basically a javascript file that instructs the closure compiler about some symbols that are defined in a third party code that it is not aware of.

i.e. If I'm using jQuery, but I can't include it into my compilation, because it is already used by other users on my site
- and jQuery is not yet friendly with the closure-compiler
- and I don't want to have two jQuery files on my site - one compiled and one not
I could define the externs I'm using in my compiled code like this:


var jQuery, $;
$.fn = jQuery.fn = {
bind: function() {
},
trigger: function() {
},
prepend: function() {
},
show: function() {
},
hide: function() {
},
append: function() {
}
};


All good, but I don't know all the public methods/properties of the APIs I'm using! Nor I want to waste time to write externs for each and every piece of code for all the extern APIs I'm using!

So, I have written a small example of how to extract all the properties / methods of a javascript object as externs.

Please leave a comment if this helps you or if you have suggestions to improve it.

9 comments:

  1. luckly I searched this before I did my own , very helpful snippet! I will take a closer look and let you know. Thanks!!

    ReplyDelete
  2. This utility is extremely useful, and really something equivalent ought to be part of the Closure distribution.

    One quick note of caution: if generate externs for jQuery, the output is browser dependent. If I run it on IE, then $.browser.msie is declared as an extern, but not $.browser.webkit. On Chrome, the opposite happens. This is because jQuery doesn't define the properties that don't correspond to the browser it's running in, so your code doesn't extern them (they're undefined, so why would it?). Hopefully I can save someone some time by pointing this out :)
    Thanks again for this fantastic utility!

    ReplyDelete
  3. You are right! Thank you for pointing out the obvious difference!
    The externs can be duplicates, so if you generate for most common browsers, then you should be safe.

    ReplyDelete
  4. Useful tool. Is it opensource?

    I was thinking to use it in my project and I would like to run it in command line, not in web interface.

    ReplyDelete
  5. You are free to use it. Just that it is limited to the web interface :(

    ReplyDelete
  6. great concept. doesn't seem to work with http://backbonejs.org though :(

    ReplyDelete
  7. Backbonejs is pretty new :) This was created 3 years ago - if you find an work around please share it so others can see it.

    Thanks!

    ReplyDelete
  8. For Backbone.js see https://gist.github.com/1847810

    --x--
    /*
    * @fileoverview Externs for backbone-0.9.1.js
    *
    * built with http://www.dotnetwise.com/Code/Externs/index.html
    * see also: http://blog.dotnetwise.com/2009/11/closure-compiler-externs-extractor.html
    * via: http://code.google.com/p/closure-compiler/wiki/FAQ#How_do_I_write_an_externs_file?
    *
    * Note: when building via that page, you first need to load in underscrore.js, as that's a dependency.
    * also, after running the extern for Backbone, you need to manually run it for:
    * Backbone.Model.prototype, Backbone.Collection.prototype, Backbone.Router.prototype,
    * Backbone.History.prototype, and Backbone.View.prototype
    * because these objects are modified using _.extend(Backbone.Model.prototype ...)
    * @see http://documentcloud.github.com/backbone/
    * @externs
    */
    --x--

    ReplyDelete

 
Blog powered up by Blogger