Fork me on GitHub
#clojurescript
<
2021-05-11
>
steveb8n00:05:22

Q: I want to use core.cache in a nodejs server. I’m pretty sure that somebody partially ported the jvm project to cljs but I can’t find it. Am I remembering incorrectly?

Pepijn de Vos10:05:00

Ohai, it's been.... a few years since I looked at ClojureScript. How are things going? http://clojurescript.org is not a great look tbh, linking prominently to several projects that are no longer maintained.

p-himik11:05:44

You mean https://clojurescript.org/community/companies ? Oh what projects do you mean exactly?

Pepijn de Vos11:05:56

https://clojurescript.org/community/libraries als lists stuff that is no longer maintained such as Om

p-himik11:05:36

I wouldn't change anything. Those libraries that exist, are written in ClojureScript, and work. http://clojurescript.org is one, the libraries are many - maintaining flags for each an every one is unfeasible IMO.

Pepijn de Vos11:05:26

Sure they work, but wouldn't you want to direct people to the good stuff... Clicking through and seeing a bunch of deprecation notices makes the ecosystem seem pretty dead.

p-himik11:05:19

How do you define "good stuff"? In the Clojure world, there's a lot of properly working libraries that haven't received a single change in years, because they just work. Some of them are even archived on GitHub - again, because there's nothing to fix, nothing to add, nothing to change.

Pepijn de Vos11:05:57

A project that straight up tells you to go use something else is a pretty low bar to clear.

Adrian Smith11:05:12

I agree the website could use updating of links and guides, there is a repo somewhere to issue PRs to do updates, if you've been away for a couple of years, then check out clj-kondo, figwheel-main, shadow-cljs, reframe/reagent are still quite good for React

p-himik11:05:49

Just because there's dust somewhere in my house doesn't mean that nobody lives there or even that nobody maintains it. :)

Pepijn de Vos11:05:45

Thanks 🙂 yea I eventually made it from the deprecated figwheel to the maintained one, which seems pretty lively.

Pepijn de Vos13:05:50

Huh, so I installed cljsjs/plotly but can't figure out how to use it

Pepijn de Vos13:05:12

(require '[cljsjs.plotly :as plotly]) works but after that plotly is not define

Pepijn de Vos13:05:10

heyyy (.newPlot js/Plotly) does something. So seems like require doesn't work quite the same...

thheller13:05:40

cljsjs packages work a bit different yes, most of them just provide some global variable you can work with

thheller13:05:02

some newer packages work properly but not everything has been updated to that style

dnolen14:05:28

@pepijndevos we could probably eliminate the Project Templates page though it hasn't really been called out before - so I dunno

dnolen14:05:55

It not clear to me that people are even looking for Project Templates any more - tools-deps was a pretty serious simplification

dnolen14:05:05

the number of things to remember kind of collapsed

Pepijn de Vos14:05:40

Hi David, good to see you're still around :)))

dnolen14:05:17

ClojureScript is alive and kicking and doing lot more stuff since the last time you were around 🙂

🙂 2
Pepijn de Vos14:05:54

I'm not aware of tools-deps. I was just looking how to set up a project, and from there eventually found figwheel-main-template

dnolen14:05:05

you don't need to setup projects

dnolen14:05:24

Clojure is more like Node.js - deps.edn is like package.json minus the bad stuff

dnolen14:05:43

after that you just use whatever you want - ClojureScript by itself, figwheel-main, shadow-cljs etc.

dnolen14:05:39

Leiningen is still supported - but it's definitely a thing people reach less and less for if you're starting something new

dnolen14:05:53

interop between Leiningen and tools-deps exists

dnolen14:05:57

for example I and the folks I work with just use ClojureScript directly

dnolen14:05:09

the days of build scripts, templates, long long gone

dnolen14:05:30

ClojureScript now has a cljs.main which replicates clojure.main and takes almost all the same arguments

dnolen14:05:05

many "tools" out there now work via CLI arguments and require no further setup

dnolen14:05:39

i.e. no more plugins

dnolen14:05:48

which wasn't ever a good idea

Pepijn de Vos14:05:50

It's a whole new world...

dnolen14:05:18

editor integration story is still a bit messy IMO

dnolen14:05:24

if you want to use whatever you want

dnolen14:05:48

Intellj + Cursive works great if you use Clojure for work and integrates well with standard REPLs

dnolen14:05:18

(and nREPL too but it has less value in that context in my opinion, the only extra you get is macroexpand from I what I can tell)

dnolen14:05:29

but don't write macros - that hasn't changed

Pepijn de Vos14:05:34

lol I tried to install some vscode thing and it yelled at me for using vim mode 😞

dnolen14:05:51

oh using random JS libraries got simpler too

dnolen14:05:06

from NPM, CLJSJS is not needed anymore

hkjels14:05:06

@dnolen Why would you say that nREPL has less value for work? Isn’t there pretty much feature-parity?

dnolen14:05:40

I've been around since before nREPL

dnolen14:05:09

nREPL obfuscates the behavior of the standard REPL which is just a very simple I/O thing

dnolen14:05:47

I've had to support it off/on for ClojureScript because it was primary tool

dnolen14:05:53

and dealing w/ it was hell

dnolen14:05:20

I have a very low opinion of it - regardless of it's utility

hkjels14:05:27

Ahh, OK.. I was thinking I was missing out maybe on some features in Cursive

dnolen14:05:28

too many bad experiences

dnolen14:05:19

and again, it's my opinion every single editor integration should start with the standard REPLs first

dnolen14:05:24

and nREPL as a second order thing

hkjels14:05:47

I’ve had a few of those bad experiences myself, but it’s been more stable as of late

dnolen14:05:00

I've lived through a decade of instability

dnolen14:05:06

so I'm done

ksd14:05:23

@dnolen have you or someone written about this? I would be curious to learn about how you set up your projects, your workflow, and how this has been impacted by nREPL instability and other such issues that may not be obvious to beginners

dnolen14:05:55

I haven't written up anything describing it - but there's a reason why ClojureScript works the way that it does

dnolen14:05:38

I generally do not want to rely on too much tooling stuff based on past experiences

dnolen14:05:20

ClojureScript is designed to be perfectly productive by itself and now exposes quite a few hooks so people don't need to write "mega-tools"

dnolen14:05:43

that's why I wrote Krell - I was tired of stuff that does N things instead of the one thing I care about

dnolen14:05:38

tired of reading docs too, tired or looking at how everything did something slightly differently for no good reason other than the questionable one of "taste"

🎯 8
💯 3
dnolen14:05:30

factor in the problems of the JS ecosystem and the whole thing felt like it was on the verge of collapse

dnolen14:05:25

so IMO ClojureScript should be self-sufficient and all the gross stuff which can't fix is kept somewhat at bay

🎯 5
ksd14:05:03

very interesting, thank you. I am relatively new to Clojure and very new to Clojurescript. I've been setting up my first project in the last few days and have had to make what seem like arbitrary choices. I wanted to go with Krell at first but then I ended up going with shadow-cljs + Expo because it seemed like I could avoid dealing with XCode that way. yesterday I read that Calva works better with figwheel so now I'm wondering whether I should use that, and I've been reading the shadow-cljs docs to figure out what the three REPLs I can connect to are, and apparently there is something wrong with my setup because the node REPL keeps saying there is no JS runtime available. also I thought it was interesting that currently I am not using tools.deps... hence my curiosity

Stuart15:05:06

I get no js runtime errors in shadow cljs until i go to page im browser. Localhost:8080. Then it works

pez15:05:00

What @U013YN3T4DA says. Do you have the app running in your browser or simulator/device?

lilactown15:05:28

if you’re running the literal Node REPL then it should automatically start the runtime, but it might depend on how you start it. cant’ quite remember the details

lilactown15:05:54

if you’re running a node-script build, then you’ll need to start the node script as a separate process

lilactown15:05:07

what exactly are you trying to REPL into? like pez said, if you want to connect to the code running on your device, then you’ll want to make sure the device is running your app and you’re connecting to the right build

ksd15:05:27

I am exploring, reading and trying to understand things. I saw there were three REPLs, or rather 2 + one per build if I understand correctly, and I am still not 100% clear on what the differences are. What I saw is that when I connected to the Node REPL (not the one for my build nor the browser one), I would get a message saying there is no JS runtime. I am doing a "regular" jack-in.

ksd15:05:00

and no I didn't have the app running on my browser or my device at that moment, although if I am understanding correctly that is separate from the Node REPL?

pez15:05:29

Indeed, but I don’t think there is a node process running when you are building a mobile app. I could be wrong about this. Starting the app on your simulator is necessary to have your REPL connected to the app.

ksd15:05:52

I see. So when the target is react-native, the node repl is not started? And if I understand correctly I can start it manually from another terminal and then connect to it from my build's REPL? I think I read this in the shadow-cljs docs

pez15:05:54

That would be true for Figwheel Main as well, so I say stick with shadow-cljs for now, it is an awesome tool.

pez15:05:49

I’ll try to see what happens if I try to connect to a plain node repl, just a minute…

ksd15:05:18

thank you!

pez15:05:44

Actually I can connect to the node-repl… I guess that makes sense, it has just never struck me that it is there.

pez15:05:00

What do you see in the Calva Jack-in Terminal pane?

pez15:05:45

Mine has

shadow-cljs - server version: 2.12.5 running at 
shadow-cljs - nREPL server started on port 55194
shadow-cljs - watching build :app
[:app] Configuring build.
[:app] Compiling ...
[:app] Build completed. (146 files, 0 compiled, 0 warnings, 2,28s)
After jack-in.

pez15:05:36

Have you started from a template or something like that?

ksd16:05:13

I get this when connecting to the node REPL:

shadow-cljs - server version: 2.12.5 running at 
shadow-cljs - nREPL server started on port 65015
shadow-cljs - watching build :app
[:app] Configuring build.
[:app] Compiling ...
[:app] Build completed. (94 files, 0 compiled, 0 warnings, 4.33s)
and no, I started from scratch. I created an Expo project then created a shadow-cljs project and kind of glued them together.

pez16:05:39

And now if you start the app on your simulator, can you connect the REPL to it?

ksd16:05:24

I can connect the node REPL to the device? or do you mean the build's REPL?

pez16:05:52

I mean the build’s REPL.

pez16:05:41

That is the important one, to get the Clojure experience in being able to modify the app you are building as it is running.

pez16:05:09

Of course, if you can’t connect Calva to the node-repl, then something is not configured as it should and that is a symptom. But the goal here should be to connect to the REPL running inside your app.

lilactown17:05:49

Node REPL in shadow-cljs parlance is a standalone REPL separate from your app

lilactown18:05:37

reading through this exchange, it’s a bit confusing. it sounds like Ray just wants to connect to the standalone Node REPL, and isn’t able to

lilactown18:05:58

the Node REPL shouldn’t require a build running or anything running on a device or browser

lilactown18:05:13

@U015GL869TQ it might be worth asking in #shadow-cljs, but I’m sure that thheller will ask you how you are starting the Node REPL. I haven’t seen how you’re attempting to start and connect to it mentioned in this thread

ksd20:05:09

@U0ETXRFEW I can connect to my app while it is running. I don't think I've configured things properly to re-evaluate forms in my editor and have the result show up in the app, but when I save it reloads twice: once by shadow-cljs (super fast!) and once by expo. so I think this is ok. @U4YGF4NGM I think what you both have said tells me what I was looking for. I'm getting the sense that there is no practical reason to connect to the Node REPL in a React Native project. And if I want to do so I need to get the Node REPL to connect to an actual Node instance which I start myself. Am I getting this? Thank you both for your input by the way!

pez20:05:36

You'll want to disable Expo/react native Fast Refresh. From the dev menu of your app.

dnolen14:05:41

all the secondary tools are great - after one understands how to use the fundamental thing

💯 6
dnolen14:05:51

this really applies to everything

dnolen14:05:19

I don't know Expo - but to me - trying to shove Android / XCode under a rug - I just don't believe in it

raspasov15:05:20

I use expo in a “bare” mode. I still use XCode, Android, etc. But I get to use their “curated” libraries which are pretty high quality. For example: https://docs.expo.io/versions/latest/sdk/in-app-purchases/ and all the others.

raspasov15:05:54

So far, I haven’t experienced any drawbacks with the “bare” approach. It is really like pure React Native (which I’ve also done multiple times).

raspasov15:05:42

I 100% agree that going with a fully managed Expo approach, at least at the moment, is questionable. A lot of limitations it seems (and they are pretty open about them).

dnolen14:05:55

these are all variations on starting in the wrong place w/ the hope that somehow the problems can be deferred

pez15:05:04

If Expo offers what you need to get your app done, then indeed it can be used to avoid dealing with Android SDK and XCode. Expo has a lot going for it, especially when it comes to distributing test versions of the app quickly.

lilactown15:05:20

I used nREPL because it’s what CIDER uses, and all of my editor config Just Works(tm) with CIDER atm

lilactown15:05:33

I use spacemacs with the Clojure layer, and I’m learning #calva rn to help our new intern. both seem to rely on CIDER

thheller15:05:13

nrepl is basically a requirement if you want basic tool support for code completion etc

raspasov15:05:43

@thheller Is that a historical accident? I mean, IntelliJ does autocompletion somehow, for all sorts of languages, without a REPL… (I am not underestimating the scope of the task, which is probably BIG). Just curious what you think.

thheller15:05:52

cursive does code completion based mostly on code analysis, not by asking the runtime for data

flowthing15:05:54

I don't see how that's true. You can have different channels for editor tooling and evals.

thheller15:05:57

I didn't mean nrepl specifically. I do not like nrepl at all, I mean a nrepl like message based protocol. not just text stream in/out, some structure

raspasov15:05:19

Yes… But it also I believe it uses nREPL when you’re in the repl window. That way you can get, for example, autocompletion (on the JVM) for example with, say, vars that you declare dynamically at runtime.

raspasov15:05:40

But that’s not a huge part of the benefit of autocompletion. It’s like 2%.

flowthing15:05:50

You can certainly get more leverage out of REPL-powered auto-completion than 2%, IMO.

flowthing15:05:29

Oh, I guess you meant the Cursive REPL window specifically. 🙂

thheller15:05:42

I can live without repl powered code completion completely. I was just using that as a basic example. there are many things a REPL may want to ask the runtime dynamically

flowthing15:05:23

That's true, but you can have one socket for the streaming REPL and another one for editor tooling.

thheller15:05:36

point is that streaming REPLs suck for tools because of the stream nature

thheller15:05:01

random prints somewhere can totally mess everything up

flowthing15:05:37

Yeah, you do want structured output, like in prepl.

flowthing15:05:54

Input can be streaming, though, and that's all that matters, really.

thheller15:05:54

prepl was the fix for that yes, but it also gave up most of its power in the process

thheller15:05:06

good luck starting a CLJS REPL from a CLJ prepl

thheller15:05:39

so instead just use a proper message based protocol from the start and all problems are solved

flowthing15:05:41

What's the problem there? It works fine as far as I can tell.

thheller15:05:01

it does not work, feel free to try it

flowthing15:05:06

I have. We might have different definitions of "works", I guess. 🙂

thheller15:05:01

what did you try? I'm talking about starting a CLJS REPL from a prepl

flowthing15:05:15

I've only taken the first steps there, though, so there might definitely be things that don't work.

thheller15:05:16

any REPL will take over the *in* and print to *out*

thheller15:05:52

but in case of prepl the *out* is captured, so all "results" from the CLJS REPL will end up as regular out messages, not actual results

thheller15:05:34

so prepl only really works if you never rebind in/out

thheller15:05:24

(which is fine, nrepl has the same problem really)

flowthing15:05:44

Oh, gotcha. That doesn't really make it unusable as far as I'm concerned, though -- it just means I don't get syntax highlighting on my results. Which is a shame, of course.

thheller15:05:55

but again .. start with a proper message based protocol and a REPL that is aware of that and you'll never have that problem

thheller15:05:34

but if you lose features you might as well skip prepl entirely ... that is my whole point

thheller15:05:46

nobody is doing this anyways so it really doesn't matter

thheller15:05:33

but from a tool perspective that makes prepl unattractive. it is also the whole reason why nrepl sucks to much for CLJS. nrepl was designed for CLJ, not CLJS and it shows.

flowthing15:05:45

I am. 😛 But yeah, like most things, it's a tradeoff. For example, I start a prepl-like thing on top of a socket REPL, which means I can do make do with zero dependencies. Also, since it's a streaming REPL, starting sub-REPLs is straightforward.

thheller15:05:26

sure .. just don't start another sub-repl from your code 😉

thheller15:05:57

no, that is cheating. you are starting a REPL that is aware of your messaging protocol. which is my entire point.

thheller15:05:28

if you design REPLs from the ground up to be aware of this all the problems go away

thheller15:05:34

or have your editor send a auto complete request while it is in a (break)

flowthing15:05:02

That works — auto-completion requests are sent over a different channel.

thheller15:05:22

but how can it then auto-complete the local context?

thheller16:05:41

but as you said .. you already built your own protocol on top of the socket repl

thheller16:05:46

so you are using what I suggested already ...

flowthing16:05:17

I'm not sure what "local context" entails here. If you mean e.g. the function parameters, it currently can't -- my plan at the moment is to implement completely inside the editor.

flowthing16:05:33

The protocol I have is 99% prepl.

flowthing16:05:54

Unstructured (streaming) input, structured output.

flowthing16:05:04

> you are starting a REPL that is aware of your messaging protocol. which is my entire point. Not sure what you mean by this. The REPL break starts isn't aware of anything. Anyway, yes, it does print results in stdout, which is a shame, but it doesn't mean it's unusable.

thheller16:05:11

never said it was unusable, just limited

flowthing16:05:41

You said "it does not work". 🙂

flowthing16:05:52

But yes, I believe it's limited.

thheller16:05:23

well yeah it doesn't work as intended, showing up as output is a good fallback but thats not the intended result

flowthing16:05:08

Yeah, it's not optimal. I guess one possible approach to explore might be to start a ClojureScript socket REPL in a different port and connect to that, instead of having both operate over the same connection.

flowthing16:05:54

Anyway, if certain bits of my output not having syntax highlighting is the price I have to pay to work with zero dependencies, it's one I'll gladly pay. 🙂 It seems very unlikely that Clojure ever gets an RPC-type of thing. Of course, it's entirely possible (probably likely) there are other downsides I just haven't come across yet, of course.

flowthing16:05:37

Good thing we had this discussion, though -- it motivated me to come up with at least one possible solution to the syntax highlighting problem. 🙂 https://tutkain.flowthing.me/sub-repl-2.mov Obviously not ideal, but it's something. 😛 If nothing else, I can use it myself (and in possible sub-REPLs built into my editor plugin).

flowthing18:05:49

Hopefully this approach covers most of my own use cases, at least: https://tutkain.flowthing.me/sub-repl.png Very glad that this topic came up. :)

thheller15:05:38

regular stream based repls are pretty hostile towards tools in general, as soon as you want more than text in/out at least

lilactown15:05:53

I know there is inf-clojure and other extensions that I can use some combo of prepl(?) + compliment and other libs but I’m not interested in figuring that out rn

dpsutton15:05:53

i've been quite happy with inf-clojure connected to socket repls and clojure-lsp. It's basically an open source version of Cursive from my experience

lilactown15:05:21

funnily I turned off code completion because it was causing perf issues in emacs

Aron15:05:31

even conjure went to nrepl instead of socket repl

dnolen15:05:11

there is an alternative - why is a REPL necessary for code completion - what about analysis?

p-himik15:05:41

You can't really do that for macro-generated code, so there's at least one reason.

raspasov15:05:43

Mmm is that a fact? Or it’s just harder?

p-himik15:05:37

You can't tell what the generated code is without actually running the macro code. That's a fact.

raspasov15:05:50

Sure, yes. I was trying to say that it’s probably possible to include a language “runtime” in the editor/IDE and run it “behind the scenes”. You don’t need to talk to a live REPL to do it, per-se.

p-himik15:05:02

Impossible in the general case. Hence, impossible at all because the editor can't know if a macro is a general case or not. A macro can be an impure function.

raspasov15:05:22

Hmmm ok. I thought of macros as just functions that do data transformations which take some data and return valid code (data). But perhaps I’m misunderstanding. Impure function as in… writes to a file or a database at expansion time? That would be quite the macro 🙂

p-himik15:05:51

A macro that uses System/getenv. Or reads a config file from CWD. Or looks at the time. Or uses (random). Or a million other things.

raspasov15:05:28

Ah, understood. Sure. I guess I never felt/had the need to write such macros which would do those things at expansion time…

raspasov15:05:16

Do you have examples of such macros in the wild? (curious to look at them)

p-himik16:05:31

Yep, cljs.test/deftest. It defines something if and only if cljs.analyzer/*load-tests* is true during macro expansion.

👌 4
p-himik16:05:05

And you can still mess things up when evaluation is required, in your own code:

(if (= (System/getenv "DEBUG") "true")
  (defn do-stuff [arg1 arg2] "some docstring" ...)
  (defn do-stuff [_ _] "noop" ...))

dnolen15:05:35

if you start packing all this analysis stuff into a REPL doesn't mean that REPL becomes harder to maintain - harder to understand

dnolen15:05:44

and less focused on what it's actually supposed to do

flowthing15:05:33

While we're on the topic... I've been working on ClojureScript editor auto-completion recently. Most of it has been relatively straightforward, but I haven't been able to figure out how to get a hold of the compiler environment in a tooling-independent manner.

dnolen15:05:41

one of the very first things Rich demoed w/ Datomic was just parsing Clojure code into Datomic

dnolen15:05:46

it was like 500 lines of code, no REPL involved

dnolen15:05:15

but somehow everybody coalesced around this more obfuscated way of doing things

dnolen15:05:20

and REPLs that are difficult to maintain

dnolen15:05:24

I already said above macroexpansion is the one thing you can't do in Cursive with standard REPLs

dnolen15:05:58

but I not desired macroexpansion in all this time

dnolen15:05:08

because the first bad idea is writing a macro that needs any kind of debugging

dnolen15:05:51

(beyond writing some unit tests)

raspasov15:05:15

Yeah… I jump to a JVM runtime in Cursive if I need to write a .cljc macro for ClojureScript.

raspasov15:05:25

(usually something basic)

dnolen15:05:48

IMO - if a macro is not blindingly obvious it should not be written

👌 3
dnolen15:05:03

if it's blindingly obvious why do you need tooling support

dnolen15:05:14

then why do you need your REPL to do this

dnolen15:05:23

what happens if you unpack all these assumptions

thheller15:05:07

so you are saying the core.async go macro shouldn't have been written? 😛

thheller15:05:35

there are definitely a few macros that aren't blindingly obvious and need proper debugging

raspasov15:05:25

Every rule has (a few) exceptions, I guess lightsaber😃

Pepijn de Vos15:05:59

So far what I really like is that cljs seems to have great JS interop while not having to touch most of the JS ecosystem.

dnolen16:05:36

@thheller or the macros written in Clojure(Script) - should people be writing these kinds of macros often outside of the foundation?

dnolen16:05:58

I'd say no, I never feel the need to this kind of macro writing in applications

dnolen16:05:23

so why focus on a feature of REPLs that is needed 0.01% of the time?

dnolen16:05:42

to me the funny result of history is that Rich attempted to fix the static analysis / REPL thing in ClojureScript - partly because it's necessary but there other benefits from decomplecting

thheller16:05:49

I've written a couple fairly complex macros too and I have needed any of the nrepl specific features for it. I'm not trying to defend nrepl in any way, it is completely terrible for CLJS. just saying that the socket REPL isnt perfect either.

dnolen16:05:10

yet then people try to turn the split around and shove back into this old way where the REPL does everything

dnolen16:05:31

I'm not defending socket REPL here

dpsutton16:05:36

> Rich attempted to fix the static analysis / REPL thing in ClojureScript what are you referring to here?

dnolen16:05:38

I'm just talking about the funny state of things

dnolen16:05:08

ClojureScript compiler is more like a library - the AST is in EDN

👍 3
dnolen16:05:49

so analysis is separated from this magic feature of the REPL capturing some var metadata

dnolen16:05:26

so in ClojureScript you get two non-intertwined useful things

dnolen16:05:52

to me if everything went this direction you're just less likely to go wrong - because each tools is only focused on what it needs to do

dnolen16:05:29

you can see this in the ClojureScript REPLs - there only a few touch points generally to call into analysis / compilation etc.