Fork me on GitHub
#shadow-cljs
<
2022-12-14
>
pez08:12:55

I'm trying to figure out how to setup a project where deps.edn is used for dependencies and add nrepl middleware (#portal in this case). Failing so far, with a message nREPL middleware: shadow.cljs.devtools.cli has no namespace. Details in 🧵

pez08:12:14

My deps.edn looks like so:

{:paths ["src" "test" "env/dev"]
 :deps {binaryage/devtools {:mvn/version "1.0.6"}
        djblue/portal {:mvn/version "0.35.0"}
        org.clojure/clojure {:mvn/version "1.11.1"}
        org.clojure/clojurescript {:mvn/version "1.11.60"}
        reagent/reagent {:mvn/version "1.1.1"}
        thheller/shadow-cljs {:mvn/version "2.20.14"}}
 :aliases {:portal {:extra-deps
                    {djblue/portal     {:mvn/version "0.35.0"}}
                    :main-opts ["-m" "nrepl.cmdline"
                                "--middleware"
                                "[cider.nrepl/cider-middleware,shadow.cljs.devtools.server.nrepl/middleware,portal.nrepl/wrap-portal]"]}}}
And shadow-cljs.edn:
{:deps {:aliases [:portal]}
 :dev-http
 {8020 "public"}
 :builds
 {:app {:target :browser
        :output-dir "public/js/compiled"
        :asset-path "/js/compiled"
        :modules {:main {:init-fn main.core/init}}
        :build-hooks [(portal.shadow.remote/hook)]
        :devtools {:preloads [devtools.preload
                              portal.setup]}}
  :test {:target :node-test
         :autorun true
         :output-to "target/node-test/tests.js"
         :ns-regexp ".*-test$"
         :build-hooks [(portal.shadow.remote/hook)]
         :devtools {:preloads [devtools.preload
                               portal.setup]}}}}
Running this:
$ npx shadow-cljs -d cider/cider-nrepl:0.28.5 watch :app :test
shadow-cljs - config: /Users/pez/Projects/shadow-portal/shadow-cljs.edn
shadow-cljs - starting via "clojure"
nREPL middleware: shadow.cljs.devtools.cli has no namespace
Jack-in process exited. Status: 2

thheller09:12:39

@U0ETXRFEW you cant set :main-opts in an alias used by shadow-cljs

thheller09:12:49

you just start via clj normally

thheller09:12:02

so I guess just clj -A:portal

thheller09:12:26

and in that REPL you start the shadow-cljs embedded server

thheller09:12:34

you just add the portal dependency as normal

thheller09:12:42

and configure the middleware in shadow-cljs.edn

thheller09:12:09

via :nrepl {:middleware [portal.nrepl/wrap-portal]}

thheller09:12:31

top level, not build level

pez09:12:19

Thanks. I'll poke around some with this. The last option I think I can't use because I'm not connecting to that nREPL server, but to the one started by clojure.

thheller09:12:44

yeah but you need to understand that the alias option with main-opts it starting its own new nrepl server

thheller10:12:00

in addition to the one start by npx shadow-cljs ...

thheller10:12:03

so pick one

thheller10:12:21

you should only need one nrepl server

thheller10:12:33

it doesn't make sense to start multiple, so just use the one provided by shadow-cljs

thheller10:12:43

and add the portal middleware to that one

thheller10:12:49

and that should be all there is to it

pez10:12:01

There are some constraints here imposed by assumptions that Calva makes. And by how output is routed for the different repls. To start with the latter. If I start the REPK with clojure and then start the shadow watchers and cljs-REPL from that REPL, then stdout is routed to the REPL and gets mixed up with REPL output. I prefer to have this output in the terminal where I start the REPL. This happens if I start shadow-cljs and let it start the REPL using clojure. I don't know why this works differently, just that it does. As for the assumptions. Calva does actually connect to the nREPL server started by shadow-cljs if I choose the shadow-cljs jack-in option. (I don't know why I thought differently.) So, in summary. Moving the portal nrepl middleware config to shadow-cljs.edn made things work exactly as I want them to. With the test runner output in the terminal and all. 🎉 Thanks again! I'll try to encode these learnings in an example project. And I will update the Calva docs. I would have had helped from that this time. 😃

thheller10:12:56

what you described doesn't make sense? you are starting via clojure but then don't use it?

thheller10:12:18

I guess I'm confused 😛

pez11:12:53

If I manage dependencies using tools-deps, then shadow-cljs starts the REPL using clojure. And also will make it start an nREPL server. I can't use that one with Portal nREPL middleware for reasons you have helped me understand here. But that's fine, since Calva will connect to the nREPL server started by shadow-cljs. Does this make sense?

pez11:12:04

Here's a template/example project wired to use start and use Portal for taps and evaluation results from both Clojure and ClojureScript REPLs. https://github.com/PEZ/shadow-portal

thheller12:12:45

the reason the tests taps don't show is because the test runtime doesn't connect to the REPL at all

thheller12:12:51

it just runs tests and exits

thheller12:12:26

if you run the tests from a regular node-repl instead they'd show up

Ertugrul Cetin10:12:45

Hi, I'm getting this error after updating shadow-cljs. Any ideas?

Exception in thread "main" Syntax error compiling at (shadow/build/closure.clj:80:3).
Caused by: java.lang.RuntimeException: Unable to find static field: ECMASCRIPT_NEXT_IN in class com.google.javascript.jscomp.CompilerOptions$LanguageMode
Here is my setup;
....
[thheller/shadow-cljs "2.20.14" :exclusions [nrepl commons-codec com.cognitect/transit-clj org.clojure/tools.reader]]
[com.google.javascript/closure-compiler-unshaded "v20221102"]
[org.clojure/clojurescript "1.11.60" :exclusions [org.clojure/tools.reader]]
....

thheller10:12:06

version conflict on the closure compiler version

thheller10:12:07

although that is the version it should be using the error indicate that this is not the version you are getting

Ertugrul Cetin10:12:36

The interesting part is, it works for my co-workers. I've also deleted .m2/repository/com/google/javascript/closure-compiler-unshaded to avoid conflict

thheller10:12:24

could be that you are getting the file from someplace else on the classpath

Ertugrul Cetin10:12:30

any possible solutions that you could have?

thheller10:12:13

open a plain REPL, then (:require ') and ( "com/google/javascript/jscomp/CompilerOptions.class")

thheller10:12:21

see where that is coming from

thheller10:12:33

should be the closure-compiler jar with the above version

thheller10:12:41

if not figure out where that came from 😛

Ertugrul Cetin10:12:28

Will do thanks 🙂

Ertugrul Cetin10:12:49

This did the trick

👍 1
pez11:12:55

What can I do to start a JS runtime for a :test build? In ^ that ^ project tests are set to :auto-run and that works great. But I can't reach the build via the REPL.

thheller12:12:34

you can't and you are not supposed to

thheller12:12:38

just use a node repl

thheller12:12:27

the test targets are for automated testing (ie. CI) and you dont want to keep those processing running due to some connected websocket

pez13:12:12

:auto-run isn't for CI, is it?

pez13:12:14

If I can I make a node repl autrun the tests for me, that would work for me. I'll see if I can make that happen.

thheller18:12:15

can you bind the run-tests function to a key and run them yourself?

thheller18:12:36

I mean I find running all tests after every change a little frustrating myself but do what you want

pez13:12:19

So, what I actually want to achieve here is to have taps happening from :auto-run tests to end up in Portal. I don't strictly need a REPL for that, but that would make it easier to examine the environment. So, then my next question is, can I hope to ba able to add a tap to these test runs?

thheller18:12:55

I don't know how portal works so I can't tell you

thheller18:12:12

if it wants to keep the node process running I can't stop it from doing so

thheller18:12:21

that would break autorun though

thheller18:12:44

the tap is in full control over what it does

pez19:12:06

@U1G869VNV knows this better than me, but as I understand it, Portal listens to a port and then the user registers a tap that submits to this port. https://github.com/djblue/portal/tree/master/src/portal/shadow When I do that from the browser app the tap reaches portal, but from the :node-test target this doesn't happen, even though it uses the same port. This is where I lose track of it and was thinking a REPL might help me.

thheller19:12:44

I don't believe it uses the REPL or any connection provided by shadow-cljs

thheller19:12:53

so its entirely on portal and its tap

thheller19:12:18

but again .. I would strongly encourage to use a REPL and runs the tests from there

thheller19:12:28

the tests targets are supposed to exit when they are done and not linger arround

djblue19:12:46

The transient node process should still be able to tap via the remote client since it's just making http post requests to the jvm process hosting the portal api

pez19:12:48

I do that already. I'm very attached to workflow of seeing shadow run my tests in a terminal pane while I work, though.