Monday, 28 February 2011

Mootools and the Closure compiler

I (and Dan over at teadriven) have been battling with the Google Closure Compiler for a few days now. I say "we". As the more javascript literate Dan has been doing the vast majority of the work while I poke things with sticks and apply googlefu to trying to find solutions to problems.

The first interesting thing is that, if you search for information about how mootools works with the closure compiler, you'll find next to nothing. There's a very brief post from 2009 claiming that mootools + closure compiler "behaves quite nicely", and a couple of posts stating that you can only use advanced optimisations on closure if you've designed your code for it, and you know what you're doing. Setting the "you need to know what you're doing" part of it aside for a moment the implication is that mootools and closure don't behave quite nicely together at all. This tallies with what we've seen. Initially we were thinking we just needed to provide an externs file for Mootools and we were a little surprised that one didn't exist in the closure contribs. Then Dan started trying to make one while I blithely disappeared to try to fix my bike, which is a whole different story. A story punctuated with increasingly irate/despairing IMs popping up on my phone as the fundamental differences of opinion between Closure and Mootools started to become apparent.

We're nearly at a point where our js has been hacked to work, but it's not a case of having made Mootools and Closure work well together. And here's some of the reasons why:

  1. Javascript sucks at object orientation. Why is that a problem? Because there's no standard way to do object orientation in javascript. Mootools and Closure approach the problem differently. Closure requires javadoc tags to help it to parse the javascript correctly, and there's currently no tag that allows you to describe a mootools-style object definition. Therefore Closure doesn't like Mootools.
  2. Closure doesn't like you messing with Element. More accurately, it doesn't like you overloading the w3c Element. Mootools does overload Element (I know, technically it doesn't, it redefines it). Therefore, Closure doesn't like Mootools.
  3. There is no externs file for Mootools. If you want to use Mootools without compiling it in to your code, you need an externs file. Currently, none exist. Therefore, Closure doesn't like Mootools. Until the other problems are solved, there's no point making one which I suppose explains this.
The last problem is relatively trivial but the first two are real issues. For the first, the best way I can see around it is for the Closure compiler code to make explicit provision for the Mootools way of doing things, probably through a specific javadoc tag. I'm sure this isn't high up the priority list for The Google. We've pulled the source, though, so there's at least the chance we'll find the time to attempt to hack such a thing in. You can sort of hack your javascript into line, though.

To create a class in Mootools, you pass in an object of properties and functions to the Class function, which then spits out a new one of the things defined by the object you passed in. There's nothing there that's inherently wrong from Closures point of view, except you need to somehow tell Closure that this is a class instantiation based upon the object you pass in (it is expecting you to be a little more traditional and create a class with a constructor function which you tag with a @constructor javadoc). Closure is, therefore, confused by what "this" you're referring to inside the class. This can hackily be resolved on a case-by-case basis by liberal use of the @this javadoc tag, which is messy. It'd be much nicer to be able to tag something as a mootools-style constructor in Closure, and that would also allow Closure to understand the object inheritance tree (which is sort of broken with this hack).

As for problem two - again, I can't really find anything on the web that talks about this. I suppose nothing else (other than mootools) really tries to overload Element, so no one else has this issue. Not entirely sure why Closure protests, or how one is supposed to tell it that you're overloading/redefining Element and no, really, that's fine. I suppose going through Mootools and renaming Element as "Mooliment" or something could, potentially, be a workaround.

Slightly frustrating to have no definitive resolution to tail this post, but there's so little information out there about this problem at time of writing that even a "mootools and closure don't work well together" post seemed like a useful contribution of sorts.