Fork me on GitHub
#shadow-cljs
<
2022-05-09
>
xfyre01:05:38

I’m not sure if this is some common question, but I searched the channel and wasn’t able to find anything. I’m using nREPL with IntelliJ IDEA, and every time after I connect to the nREPL instance I have to manually execute:

(shadow/repl :dev-android)
(ns cljs.user)
I’m wondering if this can be automated somehow?

thheller05:05:30

it cannot. well I suppose you can create a keybinding for it via custom repl commands

thheller05:05:57

the (ns cljs.user) you don't really need though?

xfyre20:05:54

without this one, I can’t execute things like (def some-binding "some stuff") - REPL assumes cljs.user namespace which doesn’t exist

thheller20:05:17

cljs.user always exists by default?

xfyre20:05:32

well, somehow - in this particular case - it doesn’t

thheller20:05:34

did you set :repl-init-ns in your build config?

thheller20:05:59

also which shadow-cljs version? there were a few where this didn't exist until a user connected, maybe you are on one of those?

xfyre20:05:17

nope, let me try that. 2.18.0

xfyre20:05:19

Connecting to remote nREPL server...
Clojure 1.10.3
(shadow/repl :dev-android)
To quit, type: :cljs/quit
=> [:selected :dev-android]
(def test-var "something")

Execution error (TypeError) at (<cljs repl>:1).
undefined is not an object (evaluating 'cljs.user.test_var = "something"')
=> :repl/exception!
(ns cljs.user)
=> nil
(def test-var "something")
=> #'cljs.user/test-var
That didn’t help. Anyway - that’s not a big deal, just a minor inconvenience, probably related to my setup.

thheller20:05:46

ah react-native. yeah some people have reported strange behavior there. can't verify since I can't get react-native running anymore

xfyre20:05:42

yeah, RN setup. ok, I’ll just keep typing stuff and probably assign shortcuts 🙂

pinkfrog13:05:08

Not sure if it could be solved with shadow. How can I retain the line number where the error occurs?

thheller15:05:19

thats react-native. it is displaying this stacktrace. dunno why the tracktrace is incomplete

danbunea16:05:50

Hi, I am trying to understand some behaviour. If I refer: ["mui-address-autocomplete" :default AddressAutocomplete] the build takes 5-8s [:web] Build completed. (12803 files, 2 compiled, 0 warnings, 7.42s) Removing the refer: [:web] Build completed. (1684 files, 2 compiled, 0 warnings, 0.90s) The lib is: "mui-address-autocomplete": "^2.0.4". Any hints?

thheller17:05:21

@danbunea 12803 files vs 1684 files explains the time difference? recompile will be faster. the files are included because I guess thats all the transitive deps of the mui-address-complete?

p-himik20:05:06

If I use --config-merge {:cache-root ".some-other-location"} and .some-other-location does not exist yet, a new shadow-cljs server instance will be started, right? Is there a better way to make sure that it's a new server instance and not an existing one? Just encountered an issue where modifying a CLJ file haven't changed the code that shadow-cljs run executes. Took me a while to realize that I had a watch running.

thheller20:05:56

config merge only merges build configs. cache root is not a build setting and as such does not have any effect

p-himik20:05:48

Ah, right. But is there a way to always start a new server for some particular command?

thheller20:05:19

just don't run it via shadow-cljs for one

thheller20:05:32

or use the --force-spawn there

thheller20:05:12

can't think of a reason why you'd do any that though?

p-himik20:05:59

Having a single server instance per project limits your development capabilities because you have to think whether you need to reload something via shadow-cljs' REPL or restart the server or whether just running it will be enough. I'd much rather have each separate CLI command just do its own thing, in isolation, without touching any global runtime.

p-himik20:05:58

> just don't run it via shadow-cljs for one Well, I use shadow.cljs.devtools.api in that script, and sounds like running it via just clj would make it more work for me, with manual start of a server instance.

thheller20:05:02

> whether you need to reload something via shadow-cljs' REPL or restart the server

thheller20:05:46

oh wait you were building a thing that was embedding shadow-cljs for something right?

p-himik20:05:28

So, I have a watch running somewhere in the background, and the same command has started a shadow-cljs server instance. Now that instance has loaded all the relevant CLJ files and all the dependencies. Fast forward a few hours, I'm about to cut a new release of the app. It requires a bunch of things and I run them all via a single call to shadow-cljs run. But my previous work has changed the release script a bit, and has added a new dependency specifically for that part. So, not thinking about it, I execute shadow-cljs run and... bad stuff happens. Old behavior, before the changes above. It was rather tedious to debug because I started to think that I had maybe a compiled and outdated class somewhere, or a copy of the script somehow. Took me a bit to realize that shadow-cljs server was running in the background.

p-himik20:05:02

> oh wait you were building a thing that was embedding shadow-cljs for something right? Not anymore, no. Well, apart from that piece of code that creates shadow-cljs config so I can figure out some run time parameters to feed them to other scripts.

p-himik20:05:15

Sounds like --force-spawn is just what I need though, as I could use it just for that release script. Still, makes me think that I myself would probably prefer an explicit flag that did the reverse. I.e. the default behavior for shadow-cljs would be to start a new server instance each time, and some flag would make it reuse some specific instance. But that's just me - I barely use that "connect to existing instance" feature.

thheller20:05:59

I mean I would probably recommend just using clj or lein for stuff like this?

thheller20:05:35

unless this "release" task is really only doing CLJS related things

thheller20:05:53

if it does something else too a more generic runner might make sense

p-himik20:05:43

But that would make me have to explicitly start shadow-cljs server, no? Given that I use shadow.cljs.devtools.api/release in that very script or watch in other places of that script.

p-himik20:05:53

Yeah, release/watch/test - they all have a bunch of non-CLJS steps that are nonetheless tied to either CLJS or something shadow-cljs-related. To be specific, I need to generate some JS code from ANTLR4 grammar before running shadow-cljs. And I need to run sass there as well, and some other CSS-related things.

thheller20:05:10

release doesn't require a server instance and doesn't start one

p-himik20:05:19

But it definitely uses an existing one! :)

thheller20:05:32

> But that would make me have to explicitly start shadow-cljs server, no?

thheller20:05:16

or I'm confused what you are talking about. server is only a thing because of watch basically. if that didn't exist there would be no server mode.

p-himik20:05:23

Right, then it would mean that for watch I'd have to use shadow-cljs run and for release I'd have to use clj. Ehh, I'd rather just pass --force-spawn to the release CLI command.

thheller20:05:27

it is still useful for most other tasks but still

thheller20:05:00

that is fine. just saying that you shouldn't start another server if a server is already running

thheller20:05:20

so whatever you do in the run don't start a server if you use --force-spawn

p-himik20:05:14

Right, makes sense. I'm not starting a server manually anywhere. There's {:shadow/requires-server true} in a couple of places, but not around the release-related code.

thheller20:05:39

well that would start a server if you run that via run

thheller20:05:24

how are you running sass?

thheller20:05:19

have you tried a setup using npm-run-all?

thheller20:05:25

I'm finding that very convenient

thheller20:05:13

pretty much my standard setup these days

p-himik20:05:44

As I mentioned - I have a lot of things other than just sass, and I can't run them all independently via npm run. There's a dependency graph, and right now it's expressed explicitly in the code:

(do-the-first-step)
(do-the-second-step)
(shadow/watch)
(do-some-css-shenanigans)
(compile-sass)

p-himik20:05:30

But starting another server is not that huge of a deal, right? It seems to take roughly 4 seconds on my end - I don't care about that amount of extra time when it's just for cutting a release.

thheller20:05:55

you are confusing me by saying server

thheller20:05:58

call it a JVM

thheller20:05:10

if you only run release related tasks then you only start a new JVM

thheller20:05:02

starting a new JVM takes time yes

p-himik20:05:43

Oh, so if I run shadow-cljs without --force-spawn where there's another instance running somewhere, it will skip starting not just a shadow-cljs server instance specifically, but a whole JVM?

thheller20:05:14

yes, thats the whole point

thheller20:05:30

starting shadow-cljs itself is cheap and fast. getting the JVM up and running is the slow part

thheller20:05:46

like 90% of the time is spent loading namespaces and stuff

p-himik20:05:01

In that case, I had a wrong mental picture. I thought it was slow to start the shadow-cljs server instance for some reason, and that two JVM instances would communicate with each other to reuse a single running shadow-cljs server instance.

thheller20:05:18

no. the shadow-cljs CLI script is written in CLJS and only runs node. that part talks to the server instance over tcp when present

thheller20:05:36

or starts a JVM if not

p-himik20:05:11

Yeah, now the whole thing is getting much clearer. :) I used to be confused about a few things in shadow-cljs code base, specifically the CLI part being written in CLJS. Thanks!