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?
Promesa looks very cool. Might come in handy if things get more complex
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.
You mean https://clojurescript.org/community/companies ? Oh what projects do you mean exactly?
https://clojurescript.org/guides/project-templates for example
https://clojurescript.org/community/libraries als lists stuff that is no longer maintained such as Om
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.
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.
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.
A project that straight up tells you to go use something else is a pretty low bar to clear.
Issues and PRs are welcome! https://github.com/clojure/clojurescript-site
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
Just because there's dust somewhere in my house doesn't mean that nobody lives there or even that nobody maintains it. :)
Thanks 🙂 yea I eventually made it from the deprecated figwheel to the maintained one, which seems pretty lively.
Huh, so I installed cljsjs/plotly but can't figure out how to use it
(require '[cljsjs.plotly :as plotly])
works but after that plotly is not define
heyyy (.newPlot js/Plotly)
does something. So seems like require doesn't work quite the same...
cljsjs packages work a bit different yes, most of them just provide some global variable you can work with
some newer packages work properly but not everything has been updated to that style
@pepijndevos we could probably eliminate the Project Templates page though it hasn't really been called out before - so I dunno
It not clear to me that people are even looking for Project Templates any more - tools-deps was a pretty serious simplification
the number of things to remember kind of collapsed
Hi David, good to see you're still around :)))
ClojureScript is alive and kicking and doing lot more stuff since the last time you were around 🙂
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
you don't need to setup projects
Clojure is more like Node.js - deps.edn
is like package.json
minus the bad stuff
after that you just use whatever you want - ClojureScript by itself, figwheel-main, shadow-cljs etc.
Leiningen is still supported - but it's definitely a thing people reach less and less for if you're starting something new
huh
interop between Leiningen and tools-deps exists
for example I and the folks I work with just use ClojureScript directly
the days of build scripts, templates, long long gone
ClojureScript now has a cljs.main
which replicates clojure.main
and takes almost all the same arguments
many "tools" out there now work via CLI arguments and require no further setup
i.e. no more plugins
which wasn't ever a good idea
It's a whole new world...
editor integration story is still a bit messy IMO
if you want to use whatever you want
Intellj + Cursive works great if you use Clojure for work and integrates well with standard REPLs
(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)
but don't write macros - that hasn't changed
lol I tried to install some vscode thing and it yelled at me for using vim mode 😞
oh using random JS libraries got simpler too
from NPM, CLJSJS is not needed anymore
@dnolen Why would you say that nREPL has less value for work? Isn’t there pretty much feature-parity?
I've been around since before nREPL
nREPL obfuscates the behavior of the standard REPL which is just a very simple I/O thing
I've had to support it off/on for ClojureScript because it was primary tool
and dealing w/ it was hell
I have a very low opinion of it - regardless of it's utility
Ahh, OK.. I was thinking I was missing out maybe on some features in Cursive
too many bad experiences
and again, it's my opinion every single editor integration should start with the standard REPLs first
and nREPL as a second order thing
I’ve had a few of those bad experiences myself, but it’s been more stable as of late
I've lived through a decade of instability
so I'm done
@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
I haven't written up anything describing it - but there's a reason why ClojureScript works the way that it does
I generally do not want to rely on too much tooling stuff based on past experiences
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"
that's why I wrote Krell - I was tired of stuff that does N things instead of the one thing I care about
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"
factor in the problems of the JS ecosystem and the whole thing felt like it was on the verge of collapse
so IMO ClojureScript should be self-sufficient and all the gross stuff which can't fix is kept somewhat at bay
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
all the secondary tools are great - after one understands how to use the fundamental thing
this really applies to everything
I don't know Expo - but to me - trying to shove Android / XCode under a rug - I just don't believe in it
these are all variations on starting in the wrong place w/ the hope that somehow the problems can be deferred
I get no js runtime errors in shadow cljs until i go to page im browser. Localhost:8080. Then it works
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.
What @qmstuart says. Do you have the app running in your browser or simulator/device?
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
if you’re running a node-script build, then you’ll need to start the node script as a separate process
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
I used nREPL because it’s what CIDER uses, and all of my editor config Just Works(tm) with CIDER atm
I use spacemacs with the Clojure layer, and I’m learning #calva rn to help our new intern. both seem to rely on CIDER
nrepl is basically a requirement if you want basic tool support for code completion etc
regular stream based repls are pretty hostile towards tools in general, as soon as you want more than text in/out at least
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
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
funnily I turned off code completion because it was causing perf issues in emacs
even conjure went to nrepl instead of socket repl
@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.
cursive does code completion based mostly on code analysis, not by asking the runtime for data
I don't see how that's true. You can have different channels for editor tooling and evals.
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
Got it.
there is an alternative - why is a REPL necessary for code completion - what about analysis?
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.
if you start packing all this analysis stuff into a REPL doesn't mean that REPL becomes harder to maintain - harder to understand
But that’s not a huge part of the benefit of autocompletion. It’s like 2%.
and less focused on what it's actually supposed to do
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.
one of the very first things Rich demoed w/ Datomic was just parsing Clojure code into Datomic
it was like 500 lines of code, no REPL involved
but somehow everybody coalesced around this more obfuscated way of doing things
and REPLs that are difficult to maintain
You can certainly get more leverage out of REPL-powered auto-completion than 2%, IMO.
Oh, I guess you meant the Cursive REPL window specifically. 🙂
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
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.
You can't really do that for macro-generated code, so there's at least one reason.
That's true, but you can have one socket for the streaming REPL and another one for editor tooling.
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).
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.
point is that streaming REPLs suck for tools because of the stream nature
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).
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?
random prints somewhere can totally mess everything up
Yeah, you do want structured output, like in prepl.
Mmm is that a fact? Or it’s just harder?
Input can be streaming, though, and that's all that matters, really.
prepl was the fix for that yes, but it also gave up most of its power in the process
good luck starting a CLJS REPL from a CLJ prepl
I already said above macroexpansion is the one thing you can't do in Cursive with standard REPLs
so instead just use a proper message based protocol from the start and all problems are solved
What's the problem there? It works fine as far as I can tell.
but I not desired macroexpansion in all this time
it does not work, feel free to try it
because the first bad idea is writing a macro that needs any kind of debugging
(beyond writing some unit tests)
I have. We might have different definitions of "works", I guess. 🙂
Yeah… I jump to a JVM runtime in Cursive if I need to write a .cljc macro for ClojureScript.
(usually something basic)
IMO - if a macro is not blindingly obvious it should not be written
what did you try? I'm talking about starting a CLJS REPL from a prepl
if it's blindingly obvious why do you need tooling support
then why do you need your REPL to do this
I've only taken the first steps there, though, so there might definitely be things that don't work.
any REPL will take over the *in*
and print to *out*
what happens if you unpack all these assumptions
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.
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
so prepl only really works if you never rebind in/out
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
That would be true for Figwheel Main as well, so I say stick with shadow-cljs for now, it is an awesome tool.
(which is fine, nrepl has the same problem really)
You can't tell what the generated code is without actually running the macro code. That's a fact.
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.
I’ll try to see what happens if I try to connect to a plain node repl, just a minute…
but again .. start with a proper message based protocol and a REPL that is aware of that and you'll never have that problem
but if you lose features you might as well skip prepl entirely ... that is my whole point
nobody is doing this anyways so it really doesn't matter
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.
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.
thank you!
so you are saying the core.async go
macro shouldn't have been written? 😛
there are definitely a few macros that aren't blindingly obvious and need proper debugging
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.
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.
Every rule has (a few) exceptions, I guess :lightsaber:😃
Actually I can connect to the node-repl… I guess that makes sense, it has just never struck me that it is there.
What do you see in the Calva Jack-in Terminal pane?
sure .. just don't start another sub-repl from your code 😉
Mine has
shadow-cljs - server version: 2.12.5 running at <http://localhost:9630>
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.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 🙂
Have you started from a template or something like that?
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.
https://tutkain.flowthing.me/sub-repl.mov You mean like this?
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.
Ah, understood. Sure. I guess I never felt/had the need to write such macros which would do those things at expansion time…
no, that is cheating. you are starting a REPL that is aware of your messaging protocol. which is my entire point.
Do you have examples of such macros in the wild? (curious to look at them)
if you design REPLs from the ground up to be aware of this all the problems go away
or have your editor send a auto complete request while it is in a (break)
That works — auto-completion requests are sent over a different channel.
but how can it then auto-complete the local context?
@thheller or the macros written in Clojure(Script) - should people be writing these kinds of macros often outside of the foundation?
but as you said .. you already built your own protocol on top of the socket repl
so you are using what I suggested already ...
I'd say no, I never feel the need to this kind of macro writing in applications
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.
so why focus on a feature of REPLs that is needed 0.01% of the time?
The protocol I have is 99% prepl.
Unstructured (streaming) input, structured output.
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
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.
yet then people try to turn the split around and shove back into this old way where the REPL does everything
I'm not defending socket REPL here
> Rich attempted to fix the static analysis / REPL thing in ClojureScript what are you referring to here?
I'm just talking about the funny state of things
ClojureScript compiler is more like a library - the AST is in EDN
so analysis is separated from this magic feature of the REPL capturing some var metadata
> 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.
so in ClojureScript you get two non-intertwined useful things
never said it was unusable, just limited
You said "it does not work". 🙂
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
you can see this in the ClojureScript REPLs - there only a few touch points generally to call into analysis / compilation etc.
But yes, I believe it's limited.
well yeah it doesn't work as intended, showing up as output is a good fallback but thats not the intended result
Yep, cljs.test/deftest
. It defines something if and only if cljs.analyzer/*load-tests*
is true during macro expansion.
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.
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" ...))
I get this when connecting to the node REPL:
shadow-cljs - server version: 2.12.5 running at <http://localhost:9630>
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.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.
And now if you start the app on your simulator, can you connect the REPL to it?
I can connect the node REPL to the device? or do you mean the build's REPL?
I mean the build’s REPL.
That is the important one, to get the Clojure experience in being able to modify the app you are building as it is running.
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.
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).
Node REPL in shadow-cljs parlance is a standalone REPL separate from your app
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
the Node REPL shouldn’t require a build running or anything running on a device or browser
@ruyvalle 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
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. :)
@pez 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. @lilactown 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!
You'll want to disable Expo/react native Fast Refresh. From the dev menu of your app.
yes!