Again, will shadow-cljs support loading cljs from node_modules?


#1

Saw updates from Lumo and it me thinking about that feature in shadow-cljs:


#2

No. Not until ClojureScript officially decides to support it.


#3

:+1:

I would like to add something, just a thought: Thomas is the maintainer and the answer is pretty clear but it would be nice to expand a bit on it.
I mean, shadow already differs in many ways from Cljs so much that even David always forwards folks asking better npm support.

Adding this would just close the loop and make it the go to tool for npm-based projects. I hoped lumo could achieve something like that - be the tool you would use for node on the server - but cljs compliance slowed that down as well. I understand a bit better why lumo cannot differ too much: the compiler is a port to JavaScript of the JS compiler - either you differ completely or you don’t - you cannot go half way.

Shadow has completely reimplemented the compiler
so it can operate freely. If we come up with a better way to handle this (not in package.json, I remember you Thomas did not like the approach, and you were motivating it thoroughly, that’s fair), I would be the one willing to change and port the solution to lumo, if Antonio likes it as well of course.


#4

I still have not heard a single compelling argument for doing this.

shadow-cljs has not completely re-implemented the compiler and the compiler has nothing to do with this whatsoever. This is all about classpath construction, which is done before the actual JVM/Clojure is even started. You cannot “fake” do this without the classpath since macros must be on the classpath. CLJS files could technically be anywhere but macros are loaded via Clojure require which only looks at the classpath.

I have nothing further to add to my previous comments on the subject.


#5

Ok yes my bad, not the compiler for sure. I still do not see what the technical issue is. Macros are loaded from the dependency npm path, lumo adds the path as classpath similarly to adding a path to any other folder.

Now, cached macros are another issue but we are not discussing about that.

I would be ok to have a custom key in package.json for instance.


#6

Make a good argument why and we can talk about adding it.

  • Why is this so important to you?
  • What do you hope to gain?
  • What is your actual problem with maven?

#7

First of all, what is compelling for someone cannot be compelling for others.

I am going to rewrite here why for me it is compelling (see also the github issue you linked).

My compelling argument for doing this is to drop Nexus. Some companies don’t want to use Maven and the complexity that it entails. In my particular case, my company wants to move away from everything Java. Too complex, unnecessary. Npm is what we’ve choosen - there are many open source implementation of npm registries and it really feels lightweight.

Lumo aside, now we are stuck in this world: we consume from npm AND maven and we have to deploy to maven. You can see why this is not ideal.

On top of that, many JS developers are used to npm way more than mvn and yes the tooling counts (right)? It would be great if ClojureScript the language could integrate fully in the npm/node ecosystem. Shadow is on the right track already :+1:


#8

That is why I’m trying to understand your motivations.

shadow-cljs is using the JVM and that is never going to change. It’s dependencies include clojure, closure-compiler (java, not the GWT variant) and undertow (java webserver) which are unlikely to ever appear on npm. If you want to eliminate Java then shadow-cljs might not be the correct choice for you.

The situation becomes worse if CLJS suddenly can appear in two places. Currently it is pretty simple with JS on npm and CLJS via maven. Not ideal but easy to separate. Dependency resolution would be a nightmare if you want to use a library that depends on a CLJS library published to npm and then another library which also depends on that library but the maven version. It could totally be done but would entail a whole lot of work that basically every tool would need to implement. lein, boot, tools.deps, cider, Cursive, …

If you must be able to resolve maven anyways it is a better situation to have the CLJS deps all in one place. If webjars didn’t inherit the version range crap from npm I maybe would start using that instead of npm altogether. npm support isn’t going anywhere but I would be glad to get rid of it personally.

I never tried setting up a custom Nexus but isn’t there is ready-made docker/vm image for this nowadays? I hear there are inexpensive hosted options available as well.

To me maven doesn’t entail any more complexity than npm. I publish shadow-cljs to both and I run lein deploy clojars and npm publish and nothing else. lein deploy your-nexus would be equally simple. shadow-cljs publish one day will hopefully be equally simple.

Yes, npm wins in the UX department and the initial setup is easier but we can learn from that and adopt the same experience for maven. There is absolutely no reason the experience could not be on par.

Ultimately npm publish creates a .tgz and uploads it somewhere and the only difference for maven is that it creates a .jar.

maven uses a more structured approach about what goes where. This is something that is desperately missing from the npm world and will become more annoying over time and I hope the JS world finds a better solution than literally having to know the path of the files you want to import. See the example from react-virtualized (dist/commonjs, really?)

import AutoSizer from 'react-virtualized/dist/commonjs/AutoSizer'

This will become even more relevant for ESM code. The JS world also just now realizes that big monolithic pre-packaged/bundled of code are not a good idea. See this report about the difference in importing antd vs antd/lib/button (again this having to know the path vs proper namespaces?).

To me npm is still in early stages and disregards many of the lessons learned with maven. maven is far from perfect as well but way more robust than npm.

Ultimately for me I want to avoid fracturing the ecosystem more than I already do. It is kind of terrible already if someone using shadow-cljs wants to publish a library that uses npm stuff when it does not work properly with other build tools.

If you want to use this library you must use shadow-cljs!

Seeing a disclaimer like that in a library is my own personal nightmare. I do not want this and nobody should be forced to use my tool. I will go out of my way to “fix” things in standard CLJS if this ever becomes a reality. That is also why I will not add anything that isn’t at least on the roadmap for normal CLJS.


#9

cut part cause it does not add anything to the conversation, sorry about that

You gave me the same reason that Antonio gave me for other ideas which, I repeat here, is fair: ClojureScript compatibility.

Let me just reiterate again that the tool of choice is really subjective. I am personally fine with mvn and never had a single problem with it. Once you start working in a team though, things change. Our team is more npm-inclined, so I am just asking around how to improve the workflow with it.

Shadow already improves our workflow greatly.


#10

This conversation has made a very good point though. Probably there are reasons behind but the choice of having ClojureScript packages to jars has implicitely created a split with the npm ecosystem. I agree duplication is bad but sometimes required - see webjars.
I am going to explore what triggered webjars and how it came to be, if anybody knows I am curious :smile:


#11

FWIW I think challenging/questioning the status quo is healthy and I do think that this is a discussion worth having. Improving the workflow is a worthy goal and after all shadow-cljs challenges the CLJS “standards” quite a bit to do so.

My fear of creating a shadow-cljs-only ecosystem of libraries may be exaggerated but I really do think that this would be harmful to CLJS overall. It is simply impractical to think that npm-only is a possibility at all for JVM-CLJS. Self-host maybe but I have no stake in that world.