After including these libraries in my local assets folder, the
fade-logo-on-scroll function worked as expected in test and development. However, once deployed to staging, the
fade-logo-on-scroll function didn’t work, and an “Uncaught TypeError: Undefined is not a function” error message appeared in the browser console.
What function is this error message referring to and why the heck is it missing? And why is it missing in staging but not in development? Just above the TypeError, you may have observed that the “zf” function name actually refers to the
:whitespace (removes comments and whitespace),
:advanced. If not specified, the optimization level defaults to simple.
Advanced compilation is more aggressive than the other types of compilation in that it renames symbols to gain performance improvements. Unfortunately, this means that the compilation process breaks references to functions defined outside of the compiled code, such as those in external jQuery libraries, since the renamed function reference doesn’t match the name of the defined function.
To fix this problem, I had to add an extern for the external library method. Google Closure allows for the use of externs. Externs are files that declare the names of external libraries functions that should not be renamed. Google Closure provides extern files for some common libraries—in fact, the project that I was working on already included the jQuery extern, which is why I didn’t see any errors for the jQuery functions.
externs/waypoints.js and included the following declaration:
Next, in the
project.clj file, specify this extern file for the
:compiler associated with the build using
:advanced optimizations. In the following example example,
:externs is a vector containing the path to each extern file. By convention, these extern files reside in the project’s externs folder.
To avoid surprises due to differences between compilation optimizations in various environments (i.e., development vs. production), it’s always a good idea to test the production compiler before deploying to staging or production. For example, I used the
lein cljsbuild auto prod command to locally build the project using the prod environment’s advanced optimization setting. This helps to avoid some potentially embarrassing ClojureScript blunders.