Two weeks ago, an experimental new feature landed in the ClojureScript compiler that allows you to specify npm packages as dependencies. António Monteiro, author of the excellent Lumo, has done a great job of making it easy to use — and explains its implementation and the ideas behind it better than I could in his blog post on the topic.

So I got excited, and as part of my latest project at Recurse, I tried using ClojureScript for Google’s Cloud Functions, which only support Node.js. The first package I wanted to include was request, the second most-depended-on one in the whole ecosystem.

Straight away I got a cryptic compiler error about one of its dependencies:

I asked about it on Slack, and it turned out to be a previously undiscovered bug in the Closure Compiler. I found a workaround, but quickly ran into more compiler errors.

What was wrong this time? It turns out that the Closure Compiler can’t handle any code that require s any of the Node.js API, aka the standard library. It took me a lot of searching and experimenting to figure this out: it’s not documented, although there is a bug report from May 2015 and a partially specced out proposal for a solution.

There is a workaround, but it’s incredibly arduous: I’d have to fork every single transitive dependency of every library I’m using, and make a change to every line that calls require to import a part of the standard library.

And it’s not just request — I tried the six most-depended on libraries, and couldn’t get any of them to work. Same with the Google Cloud Client Library for Node.js, which scuppered my dreams of being able to produce a single dead-code-eliminated JS file to run as a Cloud Function.

Note that you can require and use these libraries from ClojureScript right now, but it’s up to you to:

make sure they’re installed via npm wherever you run the code, and provide externs to the Closure Compiler

Also keep in mind that if you go down this route, you won’t benefit from dead code elimination, and you’ll have to do extra work if you want to require the packages using the ns macro. Incidentally, if you don’t want to maintain a package.json file or call npm directly, lein-npm might be your friend.

Anyway, it’s great that António and David are making progress in this area, and a bit of a shame that the next steps are apparently blocked by a massive, complex Java project (with 600+ outstanding GitHub issues).

At the same time, we’re getting even closer to being able to do serious Clojure development without touching the JVM at all, thanks to the likes of Planck (Mike Fikes is a legend), Lumo, an interesting new pure-CLJS build tool called mach, and Macchiato (Ring for Node). This is good news for anyone working on a problem that requires blazing-fast startup times, or who needs to use Node.js (e.g. if they’re using Cloud Functions).

I also want to link to some interesting points that Thomas Heller raised on the CLJS JIRA about whether ClojureScript should be coupled with a specific build tool like npm. I’m not sure where I stand yet, but I always like it when people in a community aren’t afraid to voice contrary opinions.

If anyone knows a good way to solve the problems I ran into using the new npm-deps feature, I’d love to hear about it. It might just be that I’m making some trivial mistake, after all!

[Please post comments and corrections to the Reddit thread]