Creating Externs

Juho Teperi edited this page Jan 19, 2017 · 12 revisions

Why do we need externs?

When a ClojureScript project uses external JS libraries, the external references to those libraries will be munged when compiling in Advanced Optimizations mode. This is the result of the Google Closure compiler aggressively renaming all unexported symbols. details here

(CLJS code) -----------> (Closure-safe JS Code) ------------> (Optimized JS)
                 |                ^                   |
                CLJS              |         Google Closure Compiler
              Compiler            |            (Advanced Mode)
                                  | 
                                  |
                 Any external library symbols used here
                will be munged in the optimized JS unless
                  they are defined in an externs file.

Since the majority of Javascript libraries do not follow Google Closure's coding standards for advanced optimization, they cannot simply be fed into the Google Closure compiler. Thus, the compiler allows for an externs file describing which external symbols are not to be touched during optimization.

What are externs exactly?

An externs file is a normal Javascript file that only contains functions and variable declarations. Declared functions have empty bodies. Declared variables can be var statements without assignment, or can be an object containing other variables and functions.

function hello() {}
var world;
var nested = {
   foo: {},
   bar: function() {}
};

The function and variable declarations can contain optional annotations in the form of JSDoc comment tags. This is mainly useful for us to tell Google Closure which functions are constructors for defining types, and if a variable is of a specific type.

/** @interface */
function Foo() {}
Foo.prototype.bar = function() {};
/** @type {!Foo} */
var foo;

Document the extern creation process

It is useful to document the method you use to create the externs so that others will be able to update the extern if necessary. A good place for the documentation is the extern file itself.

Here are two examples:

Examples

Extra Resources

Extern Generators

Open Questions

  • How are some of the cljsjs package externs generated with so many annotations?
  • Is there a way we can automate the testing externs to some extent?