Thank you!
(defonce blog-posts (r/atom '()))
(defn get-json
[uri]
(->
(js/fetch uri)
(.then (fn [res] (js->clj (.json res) :keywordize-keys :true)))
(.catch (fn [err] (.log js/console err)))))
(-> (get-json all-posts-uri)
(.then (fn [posts]
(for [post posts]
(let [post-uri (uri post)]
(->
(get-json post-uri)
(.then (fn [post] (swap! blog-posts conj post)))))))))
Ok, that was a bit hard to reason about, but this seems to work.
This whole callback business makes me have to think of things backwards in a way.~
Very weird.
Note: the uri
and all-posts-uri
are not in the snippet.Is there a difference between (vec (concat v1 (repeat n x)))
and (vec (take n (concat v1 (repeat x)))
?
I’m facing a weird problem that I am unable to understand.
I’m iterating over a sequence and generating divs contained in a flex(reagent).
When the sequence is generated with the first form above, the flex renders with the correct wrapping. The second form has a margin that I can’t explain. And there is absolutely no other difference in the code
This makes no sense, but here is some reference
the dom is the same, the styles are the same. I’m completely stumped as to what is happening
Seems like there is a difference in that in general. Consider if v1 has more elements than n. Your resulting sequence would have 0 x’s and in the first form would have n x’s
It is not the same n between the two forms
the n in the first form is (- total-n (count v1))
whereas in the second form it is total-n
My issue isn’t with the number of elements or the content of elements per se. It seems to have something to do with the iteration across the type, and I am unable to understand why or what. There is no reason why two exact same sequences should render differently just because they were generated differently
Assuming (= v1 v2)
, then (for [x v1] [some-component x])
should necessarily equal (for [x v2] [some-component x])
given that some-component
is pure
how have you confirmed that v1 and v2 are equal?
I’ve checked both content and type. Both (= v1 v2)
and (= (type v1) (type v2))
when you check the resulting dom in the devtools inspector, what's the cause of the extra padding/margin?
@smith.adriane - that’s the weird part. Every computed property is the exact same!
all the margins, padding, borders are the exact same.
I’m using a flex-wrap
the computed properties are the same for each component and for the parent?
Yeah. Exact same!
I don't believe you 😛
are there the same number of child elements in each case?
Argh. Thanks @smith.adriane - The problem was with the count. The last div was an empty div in one of the cases that was being added by some other event 🙂
Spent the last half an hour losing my hair on this and I’ve such little hair left to begin with
"can't style s##t"
Thanks a ton. we totally forgot about it
this matches my experience with CSS
For some vague reason when the flex has only enough elements to fill a row without any spillovers it borks the margins. CSS - Clearly Screwball S**t
Wacky question, is it possible to develop a Chrome extension in Clojurescript?
Hi! 🙂 Which libraries do you use for working with numbers and time (parsing, formatting, validation, manipulation etc)?
I am transitively using foreign-libs (through a cljsjs package). This package has declared :file
and :file-min
, but it doesn't use the minified file when I do advanced compilation. How is this decided, and does it work transitively?
Maybe https://www.juxt.land/tick/docs/index.html could be of interest? It's "java.time in cljs", which is a pretty good place to start.
perfect @magnars thanks! 🙂
according to the docs: https://clojurescript.org/reference/compiler-options
• :file-min
(Optional) Indicates the URL to the minified variant of the library. This will be used in preference to `:file` if `:optimizations` is set to either `:simple` or `:advanced`.
sounds like a bug if that's not working
I agree, but I'm not sure where to start looking.
hi
I am really new to Clojurescript (and Clojure for that matter) and would like to ask the community 🙂 few things. So, I am looking around what could I start using as alternative to pure JS (React) and Typescript. Those are last on my list. I was really into Elm for a while, but elm community has some other problems too I could say. What I would like here is if I would go with Clojurescript... can I distance myself from NPM problems, how is with refactoring projects after a while. Is it any better by using CS or is pretty much the same as if I would work with React? I assume Reagent and similar follow development of React so there are changes? I read somewhere that this CS ecosystem is pretty much stable for the last 7 years... This type inference to what degree can i rely on it? With Elm ... you really get a lot of safety, but with the cost of decoupling JS World a lot and only allow interoperability via Ports
How good is CS for bigger projects?
jira, small repro and crack open the compiler are where I've looked next for this kind of thing
http://ask.clojure.org does not seem to be monitored for clojurescript, but in theory that's another option
What I meant with "can i rely on it' ... can I do something like compiler driven development.... ? like in elm?
@tomaz.bracic Type inference is mostly used for performance in CLJS, not for safety. In the CLJS or Clojure in general ecosystem there are a few tools / linters (e.g. clj-kondo) that can help you avoid making silly mistakes, but they don't provide a static type system. There is also #lsp which can help you navigate projects. If you use #calva you get both tools integrated into VSCode, which may be a good way to start, but you can make it work with any editor really. To get "safety" it's best to write a test suite. There are also runtime validation libraries like #clojure-spec and #malli which can help you. Another piece of advice: if you don't know the CLJS tooling well, start with #shadow-cljs. This makes it easy to integrate with NPM libraries, but if you are using JS libraries from NPM, naturally you are going to get the pain of breaking changes from that ecosystem. CLJS is very good for big projects. I've been working on a big project for 5 years and if I would start over, I would pick CLJS again. For bigger apps, it might also be good to look into #re-frame if you are using #reagent.
O @borkdude I really appreciate your feedback. Thanks!
@tomaz.bracic You might want to watch this talk: https://www.youtube.com/watch?v=geeK1-jjlhY
(and wow, the youtube url has geeK in it)
yea... I saw this. Nice talk... though I was a bit shocked at the beginning because my other tech is Elixir too 🙂
So what are the problems you perceive in the elm community?
Just out of curiosity.
i will have a heavy websocket based app. Elm removed support for those with 0.19 version... so you have to use ports now
I saw Sente library
Remove support for websockets...?
yes, from the core. You deal with those via ports
it works quite ok
but yea... 🙂 this decoupling from JS brings a lot of great benefits but "problems" too.
That's at least one problem you don't have to worry about in CLJS land: removing = breaking and the Clojure community (inspired by its BDFL) has a culture of not breaking, only accreting.
just need to figure it out what would be better. Still can't really shake off the feeling that the whole clojure(script) dev environment is huge... not really light. All those repl configurations, etc. Just my first impression
based on the fact... that I just stepped into this
@tomaz.bracic FWIW, I don't even use a REPL for my (browser) CLJS projects, I just rely on hot-reloading
uf... there is a lot written on this
the feeling around how the whole developoment is going on
Evan (author) ... has Elm ... at least this is the feeling... like a private / closed project put out to public for use. So when you read about complaints... (but then there is another side... who is really happy) it is really hard for some changes to happen. It is not really up for discussion
I'm sure there are starter templates for reagent apps, etc
how the future will be ... what will be supported or not
those decisions are done in really really closed group if not only in Evans head
Perhaps you could look at https://luminusweb.com/ which is a full stack tutorial / template
Clojure's development is pretty much managed the same way: a small group of people, lead by Rich Hickey, decide what's going into Clojure and what the roadmap is. The community can vote on issues, etc. But Clojure, being a Lisp, allows a lot of stuff to be done in user land so I don't perceive this as a problem (maybe even a feature), especially with the "promise" of non-breakage.
With Elm ... I saw the opportunity to have a toolset / environment that would allow me build the project and deploy it with confidence that there will probably not be any issues. And even more important... have this environment that would allow me ... to come back to the project after a year (for example) ... and change few things... and not break them. And that it would still work.
And this is a huge benefit for me as being a solo freelancer
@tomaz.bracic You can have the same with CLJS but you will have to figure out the toolset you like in the beginning. But once you have something working, you can re-use this for years on end.
i guess this is true only if you keep the distance with NPM and js libraries / packages, rigth?
yes, CLJS doesn't have any tricks to magically manage breakage from the JS ecosystem
the policy in the app I've been working on was for a long time: don't use NPM, don't use JS libs, unless you really really have to ;)
what would you say is "the go to" library in clojurescript for websockets? I was actually searching for something that would allow me to use Phoenix Channels with ease... but not sure.
In the app I'm working on I just use direct JS interop. Browsers have support for websockets, why use a library?
I think this is all the code that we have:
(defn websocket! []
(let [ws (js/WebSocket. ws-url)]
(set! (.-onopen ws) (fn [_] (reset! websocket-error-count 0)))
(set! (.-onmessage ws) (fn [ev] (on-message ws (read-string (.-data ev)) sse-fallback)))
(set! (.-onerror ws) (fn [_]
(swap! websocket-error-count inc)
(reconnect!)))))
by default... if you use phoenix templates... you get provided phoenix.js which is official js library. That handles all sorts of high level / abstract actions... towards channels i assume
https://github.com/phoenixframework/phoenix/blob/v1.4/assets/js/phoenix.js
ok, in that case, you could interop with that JS library
just use it. no need for writing a CLJS wrapper library. Interop with the host ecosystem is a feature of Clojure.
aha... so without Sente or something like that?
sente is a library which probably does something similar to your phoenix stuff: it tries to make integration between server and client easier. but if your server is already managing websockets, and it also provides this phoenix.js thing, use that, don't use sente
and with all those new terms... Leiningen, Shadow-cljs.... for purely closurescript project , a newbie ... and all that ... what would you suggest? Reagent and Re-freame did promise a lot, when I was looking at that
what kind of "stack" would help me progress
if you're only doing a CLJS project, no server side, then only shadow-cljs is what I would advise
yes, only CLJS
Just check out https://github.com/reagent-project/reagent-template
and try to make it work.
One of the things I noticed... I must admit that I am really pleasantly surprised with the fact that you are so helpful
I really appreciate
this can be really important for people like me... checking this new world of Clojure(script)
thanks!
Clojure the project is, but the Lispiness of Clojure the language makes extending it quite trivial and there is no such nonsense as found in Elm such as forbidding unsanctioned interop with the host platform - rather the opposite: interop is touted as a major strength of CLJS.
@borkdude I believe @tomaz.bracic is talking about stuff like this: "Why I'm Leaving Elm | Hacker News" https://news.ycombinator.com/item?id=22821447
Hey guys, I've been watching many Clojure talks and I would really love to use Clojure, but I can't stand the bloody JVM. And so my first question is: how does CLJS compare to CL? I know it has differences, I read a bit about it, but I'd like to hear real-world experiences, rather than just theory. Of course it doesn't have Java interop, but I don't care. It's got JS interop, that sounds perfect for me. Seems to me CLJS is primarily used with Reagent/Reframe to build web apps, but do people use it to build non-web things much at all? Such as that GH repo contains the CLJS code whereas the NPM package just includes the compiled JS? Thanks in advance for any insights 🙏:skin-tone-3:
Hey @valtteri and @quoll, thanks for the feedback. I'm currently exploring GraalVM (it has both startup time and Docker image size sorted, which is really important to me) and babashka, which looks really amazing and quite what I was after. I suppose I'd be using both. I'll definitely come back to Clojurescript for frontend dev. And so finally I can switch to Clojure now, good times!
@jakub.stastny.pt_serv I also write system utils with cljs + quickjs. No access to nodejs ecosystem but really low memory.
If anyone's interested what's my beef with JVM:
1. The startup time is killing me, I code on a free AWS EC2 instance, so it's really not fast. I'm used to MRI Ruby/Node.js startup times and would be aiming for something like that. I know that you should keep the REPL running and load your file into it, i. e. using Emacs/Cider and that's all good, but that only works during the development.
2. Secondly, you cannot pack it into a small Docker image, since one has to include the whole JRE, which takes 175MB using the openjdk-11-jre-headless
package.)
3. Stack traces.
Anyway, matter of personal preferences I suppose.
CL = Common Lisp? Or did you mean clojure?
What do you develop, what kind of apps?
The biggest difference between CLJS and Clojure is its host platform obviously. JS doesn't have threads, everything is callback-based, but in Clojure you can do true concurrency, blocking, etc.
Also Clojure is more dynamic, because you always bring the compiler with you into your application, whereas with CLJS it's not available in your build (in the mainstream case).
If startup time is killing you, then take a look at graalvm, which can compile your entire app into a single binary with instant startup time.
For scripting (in the sense of bash build scripts) you can use babashka, which is a Clojure interpreter with instant startup. It's not a full replacement, but covers what you typically do when writing scripts around your main application.
Do development on a performant machine and deploy the production code to AWS. Or check the oracle cloud which offers free VM and the ARM ones are pretty good. 4cpu 24G ram. Slow JVM startup can be mitigated with 'reloadable' workflow and REPL. Check https://www.youtube.com/watch?v=gIoadGfm5T8, https://pragprog.com/titles/dswdcloj3/web-development-with-clojure-third-edition/, https://luminusweb.com/docs/repl.html Docker: someone reported 42MB here https://stackoverflow.com/questions/40958062/how-to-reduce-my-java-gradle-docker-image-size. Or do you consider graalvm https://www.graalvm.org/reference-manual/native-image/? (I have no production experience)
As far as the whole JRE thing goes - you can make a reduced JRE using the new module system stuff, so its not a huge blocker https://openjdk.java.net/jeps/282
generally though, while some people do use clojurescript on the backend it is probably one of the least common uses of clojure
that being said, it works. idk what the standard is nowadays, but i remember this https://github.com/anmonteiro/lumo
@borkdude sorry, I meant CL = Clojure. I mostly develop system utilities (out of my work that is), so nothing long-running. Interesting about GraalVM, I didn't know I can do that! Single binary with instant startup time would definitely solve my pain points there, I'll check it out. Babashka also sounds cool 😎
@zengxh thanks, will take a look. 24GB RAM/4 CPU free? Not sure if I believe it :) I will check though. 42 MB Docker image would be great, I will check GraalVM then!
@emccue interesting, I wasn't aware of the module system either, cheers!
OK, so what seems to be the consensus is that very few people run Clojure (ClojureScript that is) on the server on one of the JS platforms such as Node.js, but rather everyone seems to prefer JVM (or GraalVM). I will check that out then. What you guys said about GraalVM does sound promising!
There is also a #graalvm channel. Here is a small tutorial. https://github.com/borkdude/jayfu The talk about this project will come online soon.
Cool @borkdude, I'm checking it out.
Hey all, js interop question here. I am trying to understand how to invoke a js function that looks like this.load.image('imagekey', 'assets/pics/imagename.png');
in Clojurescript.
For example, https://github.com/photonstorm/phaser3-examples/blob/master/public/src/textures/get%20pixels.js#L14-L17 from the http://phaser.io project.
I’ve discovered http://clojurescriptmadeeasy.com/blog/how-to-use-this-in-cljs.html to get at this
, but I’m still stumped on the rest. I’ve tried (.image (.load this) key path)
as well as (.image (.-load this) key path)
but to no avail. I am sure it’s something simple. Any ideas?
Can't really tell what's going on. If you create a minimal reproducible example with the exact steps on how to build and run it, I could take a look.
Thanks. Yeah, I’ll try to do that and post it.
Ok, figured it out and wanted to close the loop. Your example,
(let [load (.-load this)
image (.bind (.-image load) load)]
(image key path))
does indeed work. I think my mistake was var-quoting the calling function. js interop is definitely different than Java.
Anyways, thanks for the help!For system utils Babashka sounds like a perfect fit. However there’s nothing wrong going with Node & CLJS either. Especially if you’re already familiar with the Node & npm ecosystem. I’ve done a few Node projects with CLJS and deployed them to AWS Lambda.
Before Babashka I actually did a lot of tools using ClojureScript on node. I still use a few of them. I’ve had to wrap a few things (like I/O), but it’s a nice platform to use. And the cljs
repl is easy to start up now
GraalVM is nice, but I would prefer to use it for large projects only (which I’ve only just started doing), because the compile time is extremely frustrating.
(.image (.-load this) key path)
will work only if this.load.image
does not need this
(which is this.load
for it).
If it does need it, you will have to find the function first.
(let [load (.-load this)
image (.bind (.-image load) load)]
(image key path))
do I understand correctly that I should expect resolve
to break when using advanced compilation? I would like to use resolve
on symbols referring to clojurescript vars, e.g. (resolve '=)
, (resolve clojure.string/includes?)
and it appears to work in my dev repl, but name mangling in advanced compilation will disrupt this, right?
given that it can only resolve symbols statically it'll be fine in advanced. unlike CLJ the use of resolve
in CLJS is pretty limited
ah, yes I see, it is expecting a symbol as input 😢 thanks, guess i'll have to find another way
FWIW any kind of dynamic lookup will break in :advanced
, unless all the things you look up are ^:export
'd
maybe @lgessler can back up a bit and explain what problem he's trying to solve?
chances are that resolve
isn't the right answer
the situation is that I have an AST describing a kind of query on entities, where one kind of AST node is a clojure function applied with args to that entity, e.g. ['= :my-entity-field "foo"]
, which would result in the query interpreter executing (= (:my-entity-field entity) "foo")
i want the AST to be trivially serializable which is why i'm not just putting the function in it directly
just use a hash-map of all the possible functions supported in your AST/DSL
unless you need a full blown interpreter, you could also look at https://github.com/borkdude/sci
yeah, that's what I was thinking--set up a function registry mapping symbols to functions and populate it once by walking supported namespaces
advanced compilation will cut out functions that might be needed by your interpreter, so you need to hold on to them by some way anyway
oh yeah good point
this is essentially what sci is also doing
FWIW I have a similar thing here https://github.com/thheller/shadow-cljs/blob/master/src/main/shadow/remote/relay/simple_query.clj
just using a multi-method, works great and is easily extensible
ooh that's very similar to what we have, except your code is much cleaner! thanks for mentioning it, good to know this design's been successfully used elsewhere 🙂
yeah, the serializable part was very important and things work great. could use symbols too but I didn't want to deal with quoting 😉
yeah heh keywords might make things a little more comfortable
That’s a GOOD policy!