Can't run shadow-cljs 4.2.1. Embedded example

ru@ru-sitrol:~$ cd clojure/ru-shadow/
ru@ru-sitrol:~/clojure/ru-shadow$ lein repl
nREPL server started on port 44311 on host 127.0.0.1 - nrepl://127.0.0.1:44311
REPL-y 0.4.4, nREPL 0.8.3
Clojure 1.11.1
OpenJDK 64-Bit Server VM 11.0.20.1+1-post-Ubuntu-0ubuntu122.04
Docs: (doc function-name-here)
(find-doc “part-of-name-here”)
Source: (source function-name-here)
Javadoc: (javadoc java-object-or-class-here)
Exit: Control+D or (exit) or (quit)
Results: Stored in vars *1, *2, *3, an exception in *e

ru-shadow.core=> (require '[shadow.cljs.devtools.server :as server])
nil
ru-shadow.core=> (server/start!)
Nov 25, 2023 8:53:25 PM io.undertow.Undertow start
INFO: starting server: Undertow - 2.3.10.Final
Nov 25, 2023 8:53:25 PM org.xnio.Xnio
INFO: XNIO version 3.8.8.Final
Nov 25, 2023 8:53:25 PM org.xnio.nio.NioXnio
INFO: XNIO NIO Implementation Version 3.8.8.Final
Nov 25, 2023 8:53:25 PM org.jboss.threads.Version
INFO: JBoss Threads version 3.5.0.Final
shadow-cljs - server version: 2.26.0 running at http://localhost:9630
shadow-cljs - nREPL server started on port 37321
:shadow.cljs.devtools.server/started
ru-shadow.core=> (require '[shadow.cljs.devtools.api :as shadow])
nil
ru-shadow.core=> (shadow/compile :app)
[:app] Compiling …
The required namespace “react-dom” is not available, it was required by “reagent/dom.cljs”.

:error
ru-shadow.core=>

My project.clj file is:

(defproject ru-shadow “0.1.0-SNAPSHOT”
:description “FIXME: write description”
:url “http://example.com/FIXME
:license {:name “EPL-2.0 OR GPL-2.0-or-later WITH Classpath-exception-2.0”
:url “Eclipse Public License 2.0 | The Eclipse Foundation”}
:resource-paths [“src/clojure”]
:dependencies [[org.clojure/clojure “1.11.1”]
[org.clojure/clojurescript “1.11.60”]
[thheller/shadow-cljs “2.26.0”]
[reagent/reagent “1.2.0”]
[cljsjs/react “17.0.2-0”]
[cljsjs/react-dom “17.0.2-0”]]
:repl-options {:init-ns ru-shadow.core})

My shadow-cljs.edn file is:

{:source-paths
[“src/clojure”]

:dependencies
[[day8.re-frame/tracing “0.6.2”]]

:builds
{:app {:target :browser
:output-dir “resources/public/js”
:asset-path “/js”
:modules
{:app {:init-fn animal-form.core/init}}
:dev
{:compiler-options
{:closure-defines
{re-frame.trace.trace-enabled? true
day8.re-frame.tracing.trace-enabled? true}}}
:release
{:build-options
{:ns-aliases
{day8.re-frame.tracing day8.re-frame.tracing-stubs}}}}}}

My goal is to run shadow-cljs embedded in a Clojure application without using npm.
Any help would be greatly appreciated.
Sincerely,
Ru

You can run shadow-cljs without node/npm, but you still need something to get and install the npm packages. react-dom is such a package. shadow-cljs doesn’t particularly care where you get it from, but you need to get it as there is no support for CLJSJS packages.

Usually just npm install react-dom, or if you really want to avoid installing npm you can do that via docker. The exact command I don’t know but there are docker images that provide node and you just need to get the file structure npm install creates.

If running npm via a container is suitable for you, here’s what I use (I wrote it for zsh with podman - no clue whether it’ll work with bash and/or docker, but it should):

npm () {
	if [[ $1 == run ]]
	then
		command npm "$@"
	else
		podman run -it -e "TERM=xterm-256color" -v ./:"/root/${PWD##*/}" -w "/root/${PWD##*/}" node:slim npm "$@"
	fi
}

Forgot to mention that I also added a :node-via-docker true config option to shadow-cljs.edn. It is only used to run npm install for packages found via deps.cljs files, since that is the only time shadow-cljs itself actually runs npm. Just runs that through docker instead of npm directly.

It is strange that impossible use a very nice functionality of shadow-cljs in clear clojure-clojurescript ecosystem. Now I need to decide whether to use the not very elegant solutions you offer, or abandon shadow-cljs and compile the old way. In any case, thank you very much everyone.
Best regards,
Ru

Nothing strange about it. You can use shadow-cljs without any npm just fine, just don’t use any npm packages.

If you however want to use npm packages, which most people do, then it is best to use them directly. CLJSJS has always been a less then ideal workaround, and has been deprecated for that very reason. Even with other tools it is now considered best practice to use npm directly, but the choice is yours.

OK. So, how to compile without npm packages? As you can see above your “4.2.1 Embeded” example is not working without npm package “react-dom”…

reagent uses react, which is a npm package. Thus it won’t work without.

I understand your reluctance to use npm, I’m not a fan either. Yet, I chose it for shadow-cljs because it makes sense. Point is that you cannot use shadow-cljs if you insist on zero-tolerance npm, but still want to use npm packages. Well, I can send you a zip file with the packages to make reagent happy if you want, but other than that you’ll have to choose something else.

Thank you, Thomas. I understand your motivation. By the way, I am impressed of https://ask.clojure.org/index.php/10403/pros-and-cons-figwheel-vs-shadowcljs I have to think it all about. It will be great if you send me the needed zip file. Thanks in advance!

Sure, here is a zip with react and react-dom. That should be enough to get reagent going. Just unzip into your project directory.

https://code.thheller.com/data/react+react-dom.zip

The package.json and package-lock.json aren’t necessary for shadow-cljs, but may be useful should you ever decide to install an additional npm package. :wink:

It seems like compilation begins… But:

ru@ru-sitrol:~/clojure/ru-shadow0$ lein repl
nREPL server started on port 41975 on host 127.0.0.1 - nrepl://127.0.0.1:41975
REPL-y 0.4.4, nREPL 0.8.3
Clojure 1.11.1
OpenJDK 64-Bit Server VM 11.0.20.1+1-post-Ubuntu-0ubuntu122.04
Docs: (doc function-name-here)
(find-doc “part-of-name-here”)
Source: (source function-name-here)
Javadoc: (javadoc java-object-or-class-here)
Exit: Control+D or (exit) or (quit)
Results: Stored in vars *1, *2, *3, an exception in *e

user=> (require '[shadow.cljs.devtools.server :as server])
nil
user=> (server/start!)
Nov 27, 2023 10:46:55 AM io.undertow.Undertow start
INFO: starting server: Undertow - 2.3.10.Final
Nov 27, 2023 10:46:55 AM org.xnio.Xnio
INFO: XNIO version 3.8.8.Final
Nov 27, 2023 10:46:55 AM org.xnio.nio.NioXnio
INFO: XNIO NIO Implementation Version 3.8.8.Final
Nov 27, 2023 10:46:55 AM org.jboss.threads.Version
INFO: JBoss Threads version 3.5.0.Final
shadow-cljs - server version: 2.26.0 running at http://localhost:9630
shadow-cljs - nREPL server started on port 36717
:shadow.cljs.devtools.server/started
user=> (require '[shadow.cljs.devtools.api :as shadow])
nil
user=> (shadow/compile :app)
[:app] Compiling …
IllegalArgumentException: No matching method legacySetOutputFeatureSet found taking 1 args for class com.google.javascript.jscomp.CompilerOptions
clojure.lang.Reflector.invokeMatchingMethod (Reflector.java:127)
clojure.lang.Reflector.invokeInstanceMethod (Reflector.java:102)
shadow.build.closure/set-options (closure.clj:167)
shadow.build.closure/set-options (closure.clj:123)
shadow.build.closure/convert-goog* (closure.clj:2373)
shadow.build.closure/convert-goog* (closure.clj:2338)
shadow.build.closure/convert-goog (closure.clj:2517)
shadow.build.closure/convert-goog (closure.clj:2467)
shadow.build.compiler/maybe-closure-convert (compiler.clj:1252)
shadow.build.compiler/maybe-closure-convert (compiler.clj:1245)
shadow.build.compiler/compile-all (compiler.clj:1487)
shadow.build.compiler/compile-all (compiler.clj:1364)
shadow.build.api/compile-sources (api.clj:261)
shadow.build.api/compile-sources (api.clj:253)
shadow.build/compile (build.clj:512)
shadow.build/compile (build.clj:493)
shadow.cljs.devtools.api/compile* (api.clj:296)
shadow.cljs.devtools.api/compile* (api.clj:292)
shadow.cljs.devtools.api/compile!/body-fn–20729–auto----20815 (api.clj:305)
shadow.cljs.devtools.api/compile! (api.clj:303)
shadow.cljs.devtools.api/compile! (api.clj:300)
shadow.cljs.devtools.api/compile (api.clj:312)
shadow.cljs.devtools.api/compile (api.clj:307)
shadow.cljs.devtools.api/compile (api.clj:309)
shadow.cljs.devtools.api/compile (api.clj:307)
user/eval24839 (form-init16833473627034631993.clj:1)
user/eval24839 (form-init16833473627034631993.clj:1)
clojure.lang.Compiler.eval (Compiler.java:7194)
clojure.lang.Compiler.eval (Compiler.java:7149)
clojure.core/eval (core.clj:3215)
clojure.core/eval (core.clj:3211)
nrepl.middleware.interruptible-eval/evaluate/fn–949/fn–950 (interruptible_eval.clj:87)
clojure.core/apply (core.clj:667)
clojure.core/with-bindings* (core.clj:1990)
clojure.core/with-bindings* (core.clj:1990)
nrepl.middleware.interruptible-eval/evaluate/fn–949 (interruptible_eval.clj:87)
clojure.main/repl/read-eval-print–9206/fn–9209 (main.clj:437)
clojure.main/repl/read-eval-print–9206 (main.clj:437)
clojure.main/repl/fn–9215 (main.clj:458)
clojure.main/repl (main.clj:458)
clojure.main/repl (main.clj:368)
nrepl.middleware.interruptible-eval/evaluate (interruptible_eval.clj:84)
nrepl.middleware.interruptible-eval/evaluate (interruptible_eval.clj:56)
nrepl.middleware.interruptible-eval/interruptible-eval/fn–980/fn–984 (interruptible_eval.clj:152)
nrepl.middleware.session/session-exec/main-loop–1048/fn–1052 (session.clj:202)
nrepl.middleware.session/session-exec/main-loop–1048 (session.clj:201)
java.lang.Thread.run (Thread.java:829)

:error
user=>

Maybe you can just guess what the reason is?

Thanks in advance.

Ru

That is a dependency conflict, getting the incorrect Closure Compiler version. With project.clj it is best to only depend on shadow-cljs and not clojurescript. So either remove that dependency or place shadow-cljs first.

Yes! All work well. Thank you very much, Thomas.
Good luck!
Sincerely,
Ru