Wednesday, May 15, 2013

The day true became false

I occasionally get to work on a module that heavily uses google closure. I think the original architect wanted to use it since it because google provides a compiler and a pretty robust library for doing cross browser javascript. I also like using closure when dealing with multiple people working on a large javascript project because the compiler can enforce some rules that keep certain bad code from being checked in (besides also enforcing a linter).

The particular issue I dealt with was "fun" because I wasted an entire day trying to track down a defect that at the surface appeared to be a cross browser issue. One action would show a page in firefox, but it would show a blank page in chrome.

Initially, the strategy I took was looking at the ajax requests in developer tools and making sure that they were firing correctly at the right times. After determining that the requests were being fired, I then tried to figure out why the callbacks for the requests were not being fired.

One thing to note was that we were able to reproduce the issue when we were using the minified code, but were not able to reproduce the issue when the code was un-minified.

So, we eventually got in a window.console.log spiral, where we would put a log in a closure library module, and compile the source, test it, and eventually say WTF, and rinse repeat...

At one point, my pair programming partner noticed that one of the variables in the xhrio.js library was not behaving correctly.

I figured that somewhere in this file was a variable l, or a variable j that represented true, or false.
Sure enough, at the top of the file, I saw this:

function e(a){throw a;}var h=void 0,j=!0,k=null,l=!1;

!0 === true, and !1 === false.

I then figured that other code minifiers were doing this strategy. I looked at jQuery minified, and sure enough, everywhere was littered with !0 and !1 in the jQuery code in many truth checks and returns.
I then figured that maybe google has already addressed this issue, so I filed an issue with them.

They told me that you have to wrap your module in a private scope: https://code.google.com/p/closure-compiler/wiki/FAQ#When_using_Advanced_Optimizations,_Closure_Compiler_adds_new_var
What you do is pass a command line argument to the compiler.jar: --wrap-output "(function(){%output%})();"

But I did some digging and had a daily WTF moment... We already had this wrap output, but it was removed a few months ago, because we created a separate closure module. I don't know the reasoning behind why this was removed, but I do think there should be an option to choose to minify special keywords, or even just to do the simple find/replace of true false with !0/!1.

Anyway, now you know that if you don't use wrap-output, you could be in for a lot of pain. All you need is a third-party library to not use the var keyword on simple variables. If you don't use the var keyword, the variable will change the window scoped variable, which was where the closure minified variables were living.