Search code examples
clojurescriptclojurescript-javascript-interop

How to author agnostic JavaScript library in ClojureScript?


Let's say I have a cljs file containing the following:

(ns foo)
(defn add [x y]
  (+ x y))

and wish to make this available as a JavaScript library to non-ClojureScript devs (primarily focused on node.js). I can do this:

clj -m cljs.main -c foo

But the problem is that the output is geared towards google closure's module system (e.g. goog.require). I can set the target to none with the -t flag (as opposed to browser or node), and that... doesn't fix this. Setting it to node also doesn't fix the issue: no index.js (it's called main like in Java), no module.exports = blah blah. Seems like it's geared towards standalone, full node apps, rather than libraries.

I understand that ClojureScript uses google closure for it's own sub-modules, and I'm not necessarily looking to get rid of all of that (I'm not sure you could). And I get that es2015 native JavaScript modules are out because of their static nature.

I could massage the output by hand or by script to play nice with the npm ecosystem, but I'm surprised that there's no compiler option that can actually output a npm-friendly module. Or is there? Am I just reading --help wrong?


Solution

  • shadow-cljs supports output in a CommonJS format via :target :npm-module which does support exactly what you are asking for. Node and other JS tools (eg. webpack) can consume separate namespaces independently. The default CLJS tools do not support this mode.

    ClojureScript however is very much written with the assumption that your whole program will be optimized by the Closure Compiler. This makes it less than ideal for writing libraries to be included in other builds. Each "library" built this way will contain its own version of cljs.core and therefore will be pretty large to begin and including 2 libraries built this way is a recipe for disaster since they won't be compatible with each other.