Fixing issues that arise from advanced compilation mode with the Closure compiler can be tricky to debug. Referencing external libraries can be troublesome when the compiler doesn’t know about them. However, even when externs are sucessfully configured, things can go wrong… Here’s a quick lesson learned from fixing a function that my coworker identified as broken after advanced compilation was used.
This function uses the
twitter-text-js
library to count the length of a tweet after link shortening by calling
twttr.txt.getTweetLength()
. Our misbehaving ClojureScript function looked
something like:
1 2 3 4 |
|
Pretty straight forward: it checks to see if the external script has been before calling a function that it provides or falls back counting the number of characters.
Let’s see what the advanced compiled code looks like:
1 2 3 |
|
Spot the issue? The optimizer munged window.twttr
to window.de
even though
the extern was configured.
As you may have guessed by now,
externs are not recognized when referenced through window
.
It makes sense, but may not be immediately obvious, especially when debugging.
After all, this function only broke after advanced compilation was used.
The fixed function:
1 2 3 4 |
|
Note the use of cljs.core/exists?
, to test whether a variable exists. Simply
testing js/twttr
as boolean when the script hasn’t been evaluated would throw
a ReferenceError
.
The advanced compiled result looks like:
1 2 3 |
|
Lessons learned: reference externs directly from js/
and, more generally,
avoid js/window
unless you’re accessing one of its actual properties.
Using the advanced compiler can bring tons of little nuances like this. They’re often things you may not consider when writing code and thinking about its correctness.
In the end, a rather simple lesson learned, but hopefully it’s helpful to others.