20 July 2017
This is the fourth post in the Sneak Preview series.
Closure compiler can process AMD, CommonJS and ES6 modules giving wide support for the Node ecosystem. Even so, there are popular cases which Closure doesn’t support directly, such as React’s JSX.  Maria Geller’s Google Summer of Code work also addressed this based on a design outlined by David Nolen and a preprocessing hook has been present since version 1.7.48. However, the original design makes integration with other build tools challenging, and we’ve revised the approach to simplify such integrations.
In the original design, preprocessing was enabled by providing
a foreign-lib map. The value is a
keyword dispatch for the
cljs.closure/js-transforms multimethod. Users can
implement a new multimethod case and, for example, use Java’s built-in
However this approach creates complications for popular Clojure and ClojureScript build tools. The Clojure namespace that provides the preprocess multimethod must be loaded by the user before the ClojureScript compiler is run. While this may be feasible in an explicit build script, due to how both Leiningen and Boot isolate the build to their own classpaths, this requirement simply isn’t practical.
There are a few ways to work around the original design:
Provide a new configuration option to enumerate the namespaces to
running the compiler.
Create a relation between the multimethod dispatch keyword, and the namespace
that provides the implementation.
For example, if the keyword is namespaced, the namespace part of the keyword
could be used to
require that namespace on demand.
Both of these solutions could be implemented at the build tools or in the ClojureScript compiler directly. The first option seems circuitous from an end user perspective, and while the second option highlights the fundamental problem, using keywords for this pattern seems unidiomatic. If we simply switch to symbols from keywords, we can align with existing precedents.
The next version of ClojureScript will support symbols as the
option value. Using a fully qualified symbol makes it obvious that the value
refers to a function, and the namespace part of the symbol can be used to
automatically load the namespace on the user’s behalf.
cljsjs/babel-standalone has been updated, and provides an easy way to use Babel with ClojureScript tooling following this new pattern.
Users familiar with Clojure’s philosophy know that we prioritize simplicity above most other qualities. But, simplicity is not always at odds with ease, and in fact, has long been been a language priority with respect to interoperability with the host.