Fork me on GitHub

Its been a long time (like maybe last was in 2015?) since I had an opportunity to use CLJS @ work


Om was I think pretty new then, and I was pretty happy with it compared to react/js


I'm finding the frontend landscape a little harder to track than in 2015.... has om next stalled? it doesn't seem particularly further along than in early 2016


I'm basically writing highly interactive DOM widgets without a ton of server side state


I'm probably committing for a few months of dev at this point, so not a huge pain if I don't like what I choose, but yeah, all else being equal.....


Curious what both the exotic and stolid choices for highly dynamic frontend UX in cljs are in 2020?


Probably unless I see something very neato, I'll just go with re-frame (or mayyybe fulcro?) but I really have no idea what the tradeoffs are here


All else being equal, easy output of material UI style is a bonus


I think a react based framework is your best bet, seems to be the way to go for now in ClojureScript. Re-agent being the most popular one, with re-frame for state management.


I use rum personally, but I'm only making small toy projects, so I can't speak to more complicated projects. Though I quite like rum personally. I havn't tried re-agent as much to compare though.


And Fulcro is the new craze, but its value is with client/server interaction, so if you don't have the need for a server, I don't think Fulcro would add much benefit, might actually be tough to use it client only, but I know nothing of it, so don't take my word for it


@didibus I really appreciate your thoughts! Fulcro seems cool, but looking it over with your comments in mind, it doesn't seem applicable to my domain


It seems none of the vue-based CLJS frameworks have gotten significant traction


Ya, I have never heard of any non react based cljs lib. I heard of like one or two which tried to not use a JS lib, and do their own virtual dom, or of some using the react clones like preact, but I never heard of say using angular, vue, svelte, etc.


FWIW Fulcro works just as well for client-side only stuff, no need for a server for it to make sense. it is basically the continuation of and then some


vue, svelte, etc and others don't map well to CLJS since they are compiler-based frameworks


I stand corrected on Fulcro then.


Is there something specific about ClojureScript that prevents it from a compilation based approach?


think about it ... it just doesn't map at all. in vue you write .vue files which mix html/css/js. the html directly uses the local JS.


but the vue compiler has no understanding of CLJS so you can't just drop that in there

Daniel Tan07:05:48

isn’t cljs a “compile to javascript” language already? we also have macros for dsls


I've never used any of them, so I'm asking very naive questions here. I think I can see how they'd be hard to wrap in a CLJS shell. But I think there could be a pure CLJS library that took a similar approach no?


sure. I wrote one.


but the benefit of all the react wrappers is that you get access to the react ecosystem components


but you can't really get access to the vue ecosystem without the vue compiler/runtime


Well there you go 😛 What happened with it? (I realize that maintaining such a lib requires ton of effort and it might not be realistic for the small cljs community to do so and keep up with the web)


nothing happened with it. I'm using it and working on it. Nowhere near ready for public use but works well for my purposes.


Hum, this makes me wonder. React docs mention that one motivation to move to hooks is maybe to eventually be able to compile components ahead of time like svelte and vue does as well.


Do you think that would mean exclusively for JSX ? And thus it would leave CLJS in the dust?


no clue what kind of optimizations they have planned. I already don't like hooks so I left react behind about a year ago


What would be your recommendation then, assuming one didn't care abut leveraging anything from the existing react ecosystem, like say I just plan on writting my own UX toolkit from scratch?


if you’re interested in something a little more experimental, I’ve been working on It’s full clj/cljs. One the main benefits is that your UI can run on any platform. Currently supported platforms are Mac, Linux, and WebGL. DOM and terminal backends are in progress. Future support for Windows is planned.


@U7RJTCH6J do you have any benchmarks on how this library with WebGL compares to React or VueJS, for example?


(I'm quite interested on this library 😄)


@U3Y18N0UC I don’t have any benchmarks at the moment. The main goal of the library is to investigate what a fully functional UI library look like if it was built from scratch. Most other UI libraries are coupled to some stateful UI system (ie. the DOM). For graphics, membrane is built on abstract, logical primitives like lines, rectangles, paths, images, text, etc. The event system is composed of pure functions that operate on raw input events, (ie. mouse, keyboard, scroll, touch, etc.) Performance is an important feature for any UI library, but it’s not the main focus for membrane at the moment. It’s not going to win any awards for fastest UI library. Having said that, I’ve been pleasantly surprised with how well membrane performs for my uses cases. It feels pretty responsive even though there’s still some low hanging fruit to improve performance. Since membrane is fairly experimental, it’s been tough getting feedback. I would love any comments or critiques based off your initial impression.


Great, I'll check it out and see if I can give some initial feedback. There are some experiments I'm doing on Chlorine / Atom editor and this seems like a good library to also test and see how it integrates with everything :)


very cool! there are most certainly some rough edges so don’t hesitate to message me if you run into any issues.


it evolved a bit since then but the basic idea is still the same


in practice this looks very much like fulcro/hiccup but just doesn't use react


but yeah .. not ready for public use yet. so if you want to build something from scratch you can maybe steal some ideas but you'd have to start from scratch


not sure I'll ever get this ready for public use. quite swamped already with all the shadow-cljs stuff.


Ah ya, I don't think I meant that much from scratch 😛, just meant like where I don't mind writing my own components 😛


But that I think is one of the project I remembered when I said I've seen a few that tried a pure cljs approach


yeah there aren't that many options for pure CLJS that don't use react


Unrelated question. Say I had a nice little rum component. And I might want to publish this component as a lib, so other projects could reuse it. What would be the approach? Should I go NPM? Clojars? Also, since its a rum component? What would it look like to use it from JS, or from re-agent? Or other react frameworks?


for CLJS users you publish to clojars just like any other CLJ library. no compiled code, just source files.


for JS the story is a bit more complicated and not something a lot of people do


Hum, ya maybe I'll pass publishing it for JS consumption then. Clojars seems easy enough.


And what about the fact it uses rum? Should I somehow just have a function that return the react component? Would that be the easiest to use from any react based framework?

Daniel Tan08:05:00

I’m using hooks right now, and it’s basically a closure with memoized functions

Old account08:05:08

Can someone please suggest what (set! js/COMPILED true) may do? why is it needed? :thinking_face: In here


who does it? it isn't needed?

Old account08:05:29

added the URL to the question


no clue why they set that


Hi people, I have a quick question about js/cljs interop, how do I coerce a js #Number object to be an int please ?


this is how I use it, the id in the following snippet is then a js number

(rf/dispatch [:group/delete id])


which when I dispatch for an http delete gives me a DELETE /api/group/[object%20Object]

Daniel Tan10:05:27

sounds like less of a type coercion thing and more of a is is really a number kind of thing

Daniel Tan10:05:48

probably want to inspect the value of i’d


thanks I will check that out


I'm 99% certain I've seen an online editor somewhere that had an editor on the left side, with dom output on the right, which had built in support for reagent. But I cannot for the life of me find it anymore. Anyone have any ideas?


found it, was actually a re-frame playground:

Old account14:05:03

Please help! I am debugging for few hours. Why this always evaluates nil ?

(require '[cljs.js :refer [eval-str empty-state js-eval]])
(eval-str (empty-state)
          (str "(ns cljs.user
          (:refer-clojure :exclude [atom])
          (:require [reagent.core :as reagent])
          (def atom reagent.core/atom)"
          "I think this will be evaluation result")
          {:ns            'cljs.user
           :eval          js-eval
           :static-fns    true
           :def-emits-var false
           :load          (fn [name cb]
                            (.log js/console "---name " name)
                            (cb {:lang :clj :source ""}))
           :context       :statement}
          (fn [{:keys [error value] :as x}]
            (.log js/console "-----cb" x)
            (if error
                (def *er x)
                (js/console.error "Error: " (str error)))


@stebokas are you expecting to get the value of the last expression?

Old account15:05:48

I'v got it - the result is only available in the callback!topic/clojurescript/Qwyx2-dSe2s

Old account15:05:19

And it works now

Old account14:05:14

I expecting to see this "I think this will be evaluation result" I guess


yes the value of the last expression, in general that's not possible because JavaScript


so we don't support that

😦 4

we could probably make some special cases - but this is very minor - patch welcome for bootstrapped if you want to work on it


Howdy folks, so we just recently switched over from figwheel to shadow (yay!) and I have had some issues with getting cider-connect-cljs / cider-jack-in-cljs to eval code from my emacs. After running clj -A:server from iterm the server launches and I can build/compile the webpage successfully. The problem arises when I try to cider-connect-cljs from my emacs to eval my code. I choose localhost but when I try to enter the correct nrepl port number I get this weird error

Error running timer: (error "In 'cider-connect-cljs' source: '#[0 \\307\\300\\301\\305\\306\\304\\203\\303\\204
\\202\\310%\\311\\302\"\\207 [#[771 \\306 \\307\\300\\301G\\303%\\310!\\311=\\205\\312\\303\\313\"\\206\\314\\315A\\203)\\315\\241\\210\\205.\\316\\317!\\262\\320\\302\\205C\\321>\\205C\\302C\\322\\203V	G\\323V\\203V!\\202W\\304\\305#\")\\207 [((learner:59489 learner 59489)) nil learner:59489 (metadata) nil nil helm-set-case-fold-search completion-all-completions last emacs completion-metadata-get display-sort-function #[257 \\300\\301\"\\207 [sort helm-generic-sort-fn] 4 

(fn CANDIDATES)] nil t copy-sequence append (helm helm-fuzzy) helm-completion-in-region--initial-filter 0 completion-ignore-case helm-completion-style helm-completion--sorting-done] 13 

(fn STR PREDICATE ACTION)] nil learner:59489 nil t nil t helm-comp-read-get-candidates  helm-cr-default helm-pattern] 6]' 
 (user-error \"No linked CIDER sessions\")")
If I try to launch the server using cider-jack-in-cljs it will successfully launch the server/build but my code window will read cider[not connected] and I am unable to eval any code. Does anybody have any thoughts or insight? Thanks !


^^ the correct nrepl port I was trying to connect to was 58833 .. the learner:59489 is a previous nrepl port


Just FYI - thheller is pretty active here as well, but if you don't get any response here, you might want to ask the same thing in #shadow-cljs


Is it unreliable to really on side-effects during cljs macro expansion? I’ve read only one place that it is - due to caching and parallel builds. Specifically, contemplating how to share state during macro expansion time across possible different expansions.

(defmacro step-1 [x]
  (swap! state :x x)

(defmacro step-2 [x]
  (let [x (:x @state) y (do-something x)]
  `(more-code-stuff y)))


As far as “no side-effects” warning. I find very little on the subject, but : “Gotcha #2: Caching and :parallel-build”


Does this also mean that a macro cannot rely on analyzer state to have happened “sequentially”?


yeah thats it pretty much


such as looking at :cljs.analyzer/namespaces


in the compiler state


can I not rely on :defs and stuff to be there?


sequentially no, only guarantee is that the namespaces that were required are compiled before the current ns


if they occurred “before my macro expands”


so it has to be a separate ns


to be sure it has happened


not sure what you mean. in the current ns things happen sequentially


but with caching enabled the macros won't be called so nothing happens



(defmacro my-macro [sym] (lookup-analyzer-state sym) `(whatever))

(def foo 5)

(my-macro foo)


so here the “state” is that def affects the analyzer compilation state


(def foo 5) is guaranteed to happen before (my-macro foo) yes and the analyzer state updated accordingly


ok one step further


(defmacro my-macro [sym] (lookup-analyzer-state sym) `(whatever))
(defmacro defs-thing [sym v] `(def ~sym ~v))

(defs-thing foo 5)

(my-macro foo)


what about when the def is itself behindd a macro? 😛


I thought this was the case


so I sort of consider the def affecting the analyzer/compiler state to be a side-effect


but in a sense here, it’s more “special”


than my example where I swapped into an atom I guess?


yes but :cljs.analyzer/namespaces 'the.ns is the cache


it will be restored, your state atom won't be


Yeah, I think that makes sense now that I look at it and see what you’re saying


you state effects all happen sequentially if only looking at the current file


with multiple files they might be in parallel, depending on :require setups


if I require another ns


via :require


with caching macro-expansion might be skipped, so no side-effects


will it definitley have happened before?


I’m trying to understand how a parallel build would even work


it’d have to only do things in parallel when they weren’t dependent on each other right?


I guess that does happen a fair amount


depends on the project but generally yes


Thanks for feedback. And good blog post by the way. It seems actually pretty hard to find many details on some of these deeper topics with compilation/macros


I always end up reading your “shadow” blogs and/or some of MFikes stuff it seems.


What's the best way to have pprint go to stderr instead stdout?


which env? node?


Correct, in node


I guess (js/process.stderr.write (with-out-str (pprint foo)))


(let [pperr (with-out-str (pprint (ex-data err))] 
  (js/console.error pperr))


if cljs pprint is like clj pprint, you can just pass the error stream as an arg to pprint


oh, pprint does take the writer arg, but *err* appears not to be bound, fun


in clj, you can pprint to *err* because it exists

% clj -e '(do (println "stdout") ((requiring-resolve (quote clojure.pprint/pprint)) {:a 0 :b 1 :c 2} *err*))' 1>/dev/null
{:a 0, :b 1, :c 2}
in that snip I throw away stdout for demonstration


Thanks. Though it's kind of funny because I went through the same process before coming here. "I can just pass a writer to cljs.pprint/pprint! Oh, *err* does not exist in cljs."


I wonder how hard it would be to provide *err* - worst case it's the same as *out* but in eg. node it's definitely meaningful


That's a good question. I'm still learning my way around deftype\defmethod so I'm not particularly certain of how to wrap process.stderr with the writer interface.


ah yeah that might work too if console.error goes to stderr


Oops forgot to wrap with pprint but yes, we're on the same page. console.error does go to stderr if I recall, but I'll double check.

hipster coder17:05:34

is it advisable to play around with npm modules inside the clojure script REPL?

hipster coder17:05:52

I was trying to run the normal node REPL and it's a bit of a pain to load modules

Lone Ranger17:05:56

Super advisable! Well... maybe not advisable, but I like to do it

hipster coder17:05:20

ok, I will try it... CLJS is incredible

Lone Ranger17:05:43

!(^ ^)! it is!

Lone Ranger17:05:00

the thing you gotta look out for is .bind if you're not familiar with that

hipster coder17:05:01

I keep getting a window undefined error

Lone Ranger17:05:11

ahhhhhh that's because window IS undefined!

hipster coder17:05:13

because there is no window

hipster coder17:05:23

ya, just want to run it headless

Lone Ranger17:05:42

headless browser but not node?

hipster coder17:05:52

well, I mean, just test stuff

hipster coder17:05:58

not tied to a window object

hipster coder17:05:04

there's a window npm

hipster coder17:05:30

I'm not liking this require vs import stuff either

hipster coder17:05:35

I really hope Deno fixes that

Lone Ranger17:05:40

workflow you're going for is writing stuff in node (javascript) then dynamically loading to cljs compiled to node running on REPL?

hipster coder17:05:05

I'm going to end up running node on the JVM

Lone Ranger17:05:28

you're a space explorer, sir! As in, there are probably like, 6 people doing that

Lone Ranger17:05:39

We need to get a clojurescript conj going

hipster coder17:05:40

I know I know. Just a proof of concept

Lone Ranger17:05:54

I'm not saying it's a bad thing! space exploration is awesome!

Lone Ranger17:05:59

just... not a lot of astronauts

hipster coder17:05:01

this is my fun stuff

hipster coder17:05:14

I've hacked other langs together before doing this

hipster coder17:05:36

I am doing WebRTC

hipster coder17:05:51

Decentral Video, want to run the websockets on the Java stack

Lone Ranger17:05:36

WebRTC shouldn't need websockets, I wouldn't think. At least, not directly. Unless that's how the signal server is setup

Lone Ranger17:05:43

Doesn't mean you shouldn't use that stack tho. I think it's a great stack

hipster coder17:05:47

the Signaling server can use WebSockets

hipster coder17:05:06

I'm either going to put the chat on the webrtc, or the websockets

hipster coder17:05:17

haven't decided which yet


are you doing group chat or point to point?

hipster coder17:05:44

well, webrtc also supports groups

Lone Ranger17:05:56

need to elect a leader for that I think, right?

hipster coder17:05:00

I like the p2p encryption idea


oh neat. I haven’t seen webrtc with groups

hipster coder17:05:15

it's saying it uses a mesh

hipster coder17:05:26

it creates a mesh network, p2p, for groups

hipster coder17:05:35

and yes, it can appoint a main node

hipster coder17:05:44

so it's fault tolerant

Lone Ranger17:05:03

that must be brand new. I think for practical groups above a certain point a leader is pretty useful otherwise it turns into a lot of traffic


just from a quick google: > Mesh: For smaller groups you can establish a connection from every peer to every other one.

hipster coder17:05:31

ya, that would become crazy for large groups

hipster coder17:05:44

someone gave me a repo, 300 forks

hipster coder17:05:47

I am fixing it up

Lone Ranger17:05:51

I'm looking into using serviceworkers to handle that kind of abstraction

Lone Ranger17:05:12

just... having a hard time convincing work that this effort is worth it lol

Lone Ranger17:05:34

My argument is "c'monnnn, it'd be awwwwesome"

hipster coder17:05:52

async workers in the background to handle the mesh?

hipster coder17:05:07

now that is interesting

Lone Ranger17:05:12

service workers can do client side network proxy transparently

hipster coder17:05:33

ummm, you should get into this then

hipster coder17:05:42

I was playing around with Peer.js

hipster coder17:05:53

not sure if I should use that or roll our own

hipster coder17:05:09

I'll open source the node stuff. But the commercial level stays with Java.

Lone Ranger17:05:18

It's really not toooooooo bad. I mean it's horrible. But not bad.

hipster coder17:05:41

I changed the name. There were like 300 forks. Lots of interest.

hipster coder17:05:02

I lost my github history too... re-organizing

Lone Ranger17:05:09

I will happily make empty promises of contributing

Lone Ranger17:05:21

well meaning empty promises though!

hipster coder17:05:35

nah, only do it if its in your interest

Lone Ranger17:05:54

See that's the problem, it IS in my interest. I just get swallowed up by work all the time 😞

Lone Ranger17:05:13

If I could start finishing my work DURING work then maybe I could do other things AFTER work

hipster coder17:05:24

does your work need any of it?

hipster coder17:05:29

chat, AI, video?

Lone Ranger17:05:38

I'll DM you so as to not overly hijack this chat

David Pham20:05:23

Is it possible to wrap all functions call in ClojureScript? I would like to log/save all arguments and outputs from function calls.

David Pham20:05:54

I thought of hacking specs and the instrument function to achieve it, but not sure it is the best solution.


this may offer some clues:

👍 4