Fork me on GitHub
#clojurescript
<
2020-05-28
>
Seth06:05:10

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

Seth06:05:50

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

Seth06:05:36

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

Seth06:05:33

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

Seth06:05:40

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.....

Seth06:05:18

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

Seth06:05:51

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

Seth06:05:37

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

didibus07:05:37

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.

didibus07:05:57

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.

didibus07:05:47

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

Seth07:05:06

@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

Seth07:05:00

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

didibus07:05:44

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.

thheller07:05:52

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 om.next and then some

thheller07:05:59

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

didibus07:05:29

I stand corrected on Fulcro then.

didibus07:05:01

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

thheller07:05:45

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.

thheller07:05:09

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

didibus07:05:58

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?

thheller07:05:42

sure. I wrote one.

thheller07:05:41

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

thheller07:05:58

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

didibus07:05:19

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)

thheller07:05:12

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

didibus07:05:11

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.

didibus07:05:31

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

thheller07:05:16

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

didibus08:05:10

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?

phronmophobic14:05:43

if you’re interested in something a little more experimental, I’ve been working on https://github.com/phronmophobic/membrane. 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.

mauricio.szabo15:06:06

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

mauricio.szabo15:06:16

(I'm quite interested on this library 😄)

phronmophobic16:06:28

@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.

mauricio.szabo16:06:55

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 :)

phronmophobic16:06:16

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

thheller08:05:03

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

thheller08:05:27

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

thheller08:05:18

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

thheller08:05:54

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

didibus08:05:55

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

didibus08:05:20

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

thheller08:05:43

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

didibus08:05:10

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?

thheller08:05:52

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

thheller08:05:12

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

didibus08:05:50

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

didibus08:05:50

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

Audrius08:05:08

Can someone please suggest what (set! js/COMPILED true) may do? why is it needed? :thinking_face: In here https://github.com/status-im/status-fiddle/blob/master/src/prod/app/compile.cljs

thheller08:05:59

who does it? it isn't needed?

Audrius08:05:29

added the URL to the question

thheller08:05:42

no clue why they set that

kaffein10:05:47

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

kaffein10:05:52

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

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

kaffein10:05:38

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

kaffein11:05:41

thanks I will check that out

victorb11:05:17

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?

victorb11:05:23

found it, was actually a re-frame playground: https://day8.github.io/re-playground/

Audrius14: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")
          'dummy-symbol
          {: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
              (do
                (def *er x)
                (js/console.error "Error: " (str error)))
              value)))

dnolen14:05:37

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

Audrius15:05:48

I'v got it - the result is only available in the callback https://groups.google.com/forum/#!topic/clojurescript/Qwyx2-dSe2s

Audrius15:05:19

And it works now

Audrius14:05:14

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

dnolen14:05:33

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

dnolen14:05:40

so we don't support that

😦 1
dnolen14:05:25

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

lambduhhh15:05:43

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 !

lambduhhh15:05:17

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

p-himik15:05:21

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

mikerod16:05:58

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)
 `(some-code-stuff))

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

mikerod16:05:18

As far as “no side-effects” warning. I find very little on the subject, but : https://code.thheller.com/blog/shadow-cljs/2019/10/12/clojurescript-macros.html “Gotcha #2: Caching and :parallel-build”

mikerod16:05:49

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

thheller16:05:52

yeah thats it pretty much

mikerod16:05:21

such as looking at :cljs.analyzer/namespaces

mikerod16:05:24

in the compiler state

mikerod16:05:32

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

thheller16:05:36

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

mikerod16:05:40

if they occurred “before my macro expands”

mikerod16:05:48

so it has to be a separate ns

mikerod16:05:52

to be sure it has happened

thheller16:05:33

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

thheller16:05:55

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

mikerod16:05:00

eg.

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

(def foo 5)

(my-macro foo)

mikerod16:05:28

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

thheller16:05:40

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

mikerod16:05:04

ok one step further

mikerod16:05:33

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

(defs-thing foo 5)

(my-macro foo)

mikerod16:05:43

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

mikerod16:05:03

I thought this was the case

mikerod16:05:42

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

mikerod16:05:47

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

mikerod16:05:58

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

thheller16:05:13

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

thheller16:05:26

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

mikerod16:05:58

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

thheller16:05:19

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

thheller16:05:29

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

mikerod16:05:50

if I require another ns

mikerod16:05:54

via :require

thheller16:05:56

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

mikerod16:05:59

will it definitley have happened before?

mikerod16:05:51

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

mikerod16:05:15

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

mikerod16:05:27

I guess that does happen a fair amount

thheller16:05:11

depends on the project but generally yes

mikerod16:05:24

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

mikerod16:05:45

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

Eccentric J16:05:57

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

thheller16:05:08

which env? node?

Eccentric J16:05:59

Correct, in node

thheller16:05:24

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

Eccentric J16:05:27

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

noisesmith17:05:40

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

noisesmith17:05:10

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

noisesmith17:05:11

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

Eccentric J17:05:44

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."

noisesmith17:05:30

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

Eccentric J17:05:28

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.

thheller16:05:55

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

Eccentric J16:05:35

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

unbalanced17: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

unbalanced17:05:43

!(^ ^)! it is!

unbalanced17: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

unbalanced17: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

unbalanced17: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

unbalanced17: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

unbalanced17:05:28

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

unbalanced17:05:39

We need to get a clojurescript conj going

hipster coder17:05:40

I know I know. Just a proof of concept

unbalanced17:05:54

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

unbalanced17: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

unbalanced17:05:36

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

unbalanced17: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

phronmophobic17:05:32

are you doing group chat or point to point?

hipster coder17:05:44

well, webrtc also supports groups

unbalanced17:05:56

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

hipster coder17:05:00

I like the p2p encryption idea

phronmophobic17:05:13

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

unbalanced17: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

phronmophobic17:05:14

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

unbalanced17:05:51

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

unbalanced17:05:12

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

unbalanced17: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

unbalanced17: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.

unbalanced17: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

unbalanced17:05:09

I will happily make empty promises of contributing

unbalanced17:05:21

well meaning empty promises though!

hipster coder17:05:35

nah, only do it if its in your interest

unbalanced17:05:54

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

unbalanced17: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?

unbalanced17: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.

dvingo20:05:25

this may offer some clues: https://github.com/philoskim/debux

👍 1