JS Dependencies: In Practice

I just published the next post related to dealing with JS Dependencies in shadow-cljs.

JS Dependencies: In Practice

Please discuss.


Hey Thomas,

I’m really excited about shadow-cljs, it seems to be an opinionated clean-slate approach that leaves some of the old baggage behind. CLJSJS has always been meant to be deprecated eventually and I’m excited to see it being used less with improving JS module support.

I’m not 100% sure I’m onboard with fully deprecating :foreign-libs but I guess it remains to be seen if that becomes a real problem.

I haven’t yet had a chance to try it but I’m hoping I get to it soon and then maybe I’ll also write a Boot task. :slight_smile:

I really tried to find a way to make :foreign-libs work in a way that does not conflict with using code from npm. It can work if you update every CLJSJS package to also support the “new” require style and does not rely on a global js var. The react package was already updated to do this.

The process however has never been perfect IMHO. Not every npm package is available and keeping everything in sync is a ton of work. Is it really required if we can just use npm directly?

I thought about adding :foreign-libs as an alternate :js-provider so we can work without npm as well. We can’t mix it though so removing it seemed like the better option for now. We need to get away from the globals style so we can at least try using the Closure Compiler as :npm-deps intended.

Added a very rough Chinese translation https://segmentfault.com/a/1190000011954645

I have a question: after so many things, does it mean we can use shadow-cljs to compile JavaScript-only projects now?

As a relative newcomer to JS-land, I was hoping to use CLJSJS as an indicator of “libraries that are vetted by the ClojureScript” community, not only compatibility wise, but as a curated collection out of the half a million libraries out there. I hope I can keep using it that way :slight_smile:

Welcome to JavaScript world, there’s not standard library. We have to deal with a lot of situations. Pick what you want on GitHub!

Yes, but it is not optimized for that and never will be.

Maybe that could be a future direction for the project once the module packaging is no longer needed as much. A community maintained set of library recommendations that work well with ClojureScript and Closure.

Love the new :resolve option for all the intricacies of importing JS for various targets!

One thing this doesn’t mention is how a ClojureScript project foo can specify its own JS dependencies when required by another ClojureScript project bar. In other words, when foo requires bar, how are foo's JS dependencies expected to be resolved?

This information is already specified by foo's package.json, but for the purpose of transitivity I believe it must also be redundantly specified in foo's src/deps.cljs file, containing a map with an :npm-deps key.

Did I correctly describe this?

Yes, that is correct. Any library can add a deps.cljs to the published .jar and express JS dependencies this way.

{:npm-deps {"react" "^16.0.0"}}

Keyword keys (eg. :react) is also allowed.

shadow-cljs will install them automatically (or by calling shadow-cljs npm-deps). For CLJS itself I believe you must set :install-deps in the compiler options for these to be installed.

1 Like

Random ideas:

  • shadow-cljs add supports to npm scripts and calling shadow-cljs run x to replace yarn run x
  • shadow-cljs becomes a package manager with a command called shadow-cljs publish
  • in the command-line it got as short as npm and called sdc

than I can remove yarn and package.json from my project template :laughing:

alias sdc="npx shadow-cljs"

I’m personally not interested in writing a package manager.

I recently added clj-eval which can eval Clojure (not CLJS) code from the command line in the shadow.user namespace. The intent here is to be able to run things in a scripted way. cat script.clj | shadow-cljs clj-eval - with script.clj

(shadow/release :build)

Or just simply shadow-cljs clj-eval "(shadow/release :build)" "(+ 1 2)".

I will also add run or clj-run similar to lein run -m some.ns/fn and more args to directly calling a clojure fn. I hope that someone wants to write a shadow-cljs run some.lib/deploy-to-clojars fn. Since the code will be executed in the context of the shadow-cljs process it has full access to its API. I hope to extend this API to support more tooling needs. It will probably mirror exactly what the new clojure tool does. It might even just use that.