Fork me on GitHub
#clojurescript
<
2022-09-16
>
Ted Ciafardini13:09:08

Trying to add a 2 second delay before rendering a loading indicator in re-frame app: js for a timeout:

(defn sleep [f ms]
  (js/setTimeout f ms))
the component:
(defn loading-indicator []
  [:div [:img {:src "/img/loading.gif" :style {:width "10rem"}}]
    [:div.warning  "# LOADING #"]])
the call site:
(if @loading?
  (utils/sleep (fn [] [loading-indicator]) 2000)
  [:div.column.is-two-thirds
   [ctx-container @entry]])
The loading indicator is rendering as a seemingly random integer. “46” or “32". Been stuck on this for a bit. I’m sure it has something to do with (fn [] [loading-indicator]) - maybe my approach is totally wrong here

p-himik13:09:39

js/setTimeout returns an integer - the timeout ID. That's exactly what you're seeing.

p-himik13:09:57

Instead, have another boolean somewhere, or change loading? into state where it can be something like :loading , :loading-with-indicator, and :done. Change that variable from the first state into the second with that js/setTimeout. And that's it.

Ted Ciafardini13:09:41

thanks - just started adding a new piece of state to see if that would work

p-himik13:09:10

But since you're using re-frame, it might be better to use the built-in :dispatch-later effect instead of js/setTimeout. Especially if you consider that "loading->loading-with-indicator" distinction to be a part of the app's state.

👀 1
Ted Ciafardini13:09:11

didn’t know about dispatch-later, thank you

Ted Ciafardini13:09:16

:dispatch-later was exactly what I needed, thank you 🙂

👍 1
Dallas Surewood21:09:15

Kind of a silly question, but how does datascript work in the context of static websites? Is there a convenient way to persist a datascript db between page navigations?

lilactown21:09:11

you could serialize the db and set the string as a value of a key in local storage

Dallas Surewood21:09:34

I'm guessing that's expensive? Does datascript not jive well with traditional web apps? It's more geared towards SPAs?

lilactown21:09:36

that's right

lilactown21:09:28

clojurescript in general is more geared towards SPAs

lilactown21:09:41

datascript also works on the backend with Clojure. you could consider using it or one of the more durable versions like datalevin or asami

Dallas Surewood21:09:08

I was considering making a sort of hybrid app that uses Rum and datascript, but mostly html. But I was wondering how I might keep track of state between page transitions.

lilactown21:09:58

no matter what technology you use, if you want the backend to serve a new HTML page on each navigation you have to somehow persist the state and revive it afterward. you can do that on the backend, and send the state in the initial page request, or you can persist it in local storage

lilactown21:09:11

if you want your site to be essentially static for some other reason, then local storage is the best way

Dallas Surewood21:09:54

got it, thank you.

vemv22:09:39

Was there some trick to conditionally require stuff in cljs? My use case is: a lib may be absent from the classpath. I want to try requiring the lib. If it fails, some code should be elided at compilation time

p-himik22:09:53

Why could it be absent from the classpath?

vemv22:09:26

dependencies can be :provided and consumers may opt not to want the dep

p-himik22:09:58

But it all happens in compile time, right?

p-himik23:09:10

And how exactly does a consumer decide what dependencies to compile?

vemv23:09:41

consumer c depends on d which declares a :provided dependency p c can opt to p by explicitly depending on it

p-himik23:09:01

What is d supposed to do when p is not included by c?

vemv23:09:34

not compile the code that can't be compiled

vemv23:09:03

(defmacro when-foo-available [& body]
  (when (try (require 'foo) true (catch ,,, false))
    (do ~@body)))
fairly common pattern in jvm clojure

p-himik23:09:21

> not compile the code that can't be compiled The most robust way of achieving that is to change the classpath.

p-himik23:09:10

But not sure how viable it is if d is a jar library.

vemv23:09:51

Is there conditional require ing in clojurescript or not?

p-himik23:09:05

No, as far as I'm aware.

vemv23:09:13

thanks :thumbsup:

colinkahn23:09:23

Not sure if this solves your problem, but this exists https://github.com/borkdude/dynaload

lilactown00:09:01

you do have to make sure that your consumer requires the ns in your lib conditionally depends on, in that case

lilactown00:09:55

what I would typically do is separate the code that depends on the conditional library into a different namespace. then if the user wants to use my library foo with the conditional library bar, they can include foo.bar

lilactown00:09:28

you can then use protocols, multi methods, or some other indirection to pick the right behavior based on what the user has configured their application to use

ryrobes23:09:39

Hey all, quick question: is there a way to start a (node.js) cljs nrepl (using lein, shadow-cljs, whatever) - where an nrepl client can connect to it and automatically be in cljs mode without having to first execute a command to mode-switch? I've tried all kinds of different repl configs - but when I connect remotely (even with the cljs command pre-pended), I'm never able to get into cljs mode. Yet, locally it works fine (with the cljs command, obvs). I'm connecting via clj simply with something like...

;[nrepl.core :as nrepl]
;...
(with-open [conn (nrepl/connect :host nrepl-host :port nrepl-port)]
               (let [skt (nrepl/client conn 600)
                     msg (nrepl/message skt {:op "eval" :code s}) ... etc 
Any pointers / examples / links would be appreciated. Thanks!

lilactown00:09:50

might be a better question for #nrepl tbh. AFAICT nrepl is a Clojure REPL first, and CLJS support is sort of glommed on by using something like piggyback

ryrobes00:09:38

Good point. Yeah, clearly it is much more complex than I had first realized.

hoppy01:09:03

I routinely use nodejs shadow-cljs repl from both calva (vs-code) and cider (emacs). I use this alias (caveat - version may be out of date)

hoppy01:09:08

and it announces the port it's using, and I do a 'connect' (rather than a jack-in) on either editor to that port. calva seems to be more sophisticated at getting itself connected than cider is. for cider, need to give it the port manually (probably something I don't have set up right).

hoppy01:09:34

both of these give you choices as to what you want to repl to - and the choices are a bit vexxing.

hoppy01:09:03

in emacs, for example, you need to specify a repl type of shadow-cljs, and then the instance (aka :app in my case) if I want to actually repl into a running app. They both offer 'node-repl' as an option, which gives you a naked node that you can than eval into.

hoppy01:09:52

bear in in mind that what you are actually doing in shadow is talking to shadow-cljs, which brokers for the running app, which back-connects. It's a bit confusing, but makes sense once you get into it (and gives some very sophisticated possibilities)

ryrobes02:09:22

Appreciate the replies! I'm most-likely misunderstanding - but... Lets say I'm starting up a node-repl w

npx shadow-cljs node-repl -d cider/cider-nrepl:0.28.3
All good, starts up...
shadow-cljs - config: /home/ryanr/data-rabbit/shadow-repl/shadow-cljs.edn
[2022-09-16 22:20:10.736 - WARNING] TCP Port 9630 in use.
shadow-cljs - server version: 2.19.8 running at 
shadow-cljs - nREPL server started on port 33666
cljs.user=> shadow-cljs - #4 ready!
can execute cljs code right off the bat.
(str "Hi, from ClojureScript " *clojurescript-version*)

"Hi, from ClojureScript 1.11.60"
Great. But when I have my CLJ process connect to it via port 33666, it's still in CLJ mode
Syntax error compiling at (REPL:3:1).
Unable to resolve symbol: *clojurescript-version* in this context
I can confirm this by
(str (clojure-version))
"1.11.1"
Again, apologies if I'm missing the middleware piece in my thinking - I'm not trying to do anything fancy ATM, just get back a viable cljs repl eval from an nrepl client. Calva and Cider seem to inject a decent amt of machinery to get this to work, no?

thheller05:09:43

suppose you do npx shadow-cljs server and connect to the nrepl server via .shadow-cljs/nrepl.port. all you need to eval to switch that CLJ to node CLJS REPL is (shadow.cljs.devtools.api/node-repl)

thheller05:09:56

so, you just need a nrepl client that can eval one thing on connect

thheller05:09:46

other clients usually issue a nrepl clone first so they keep the CLJ session in addition to the CLJS session

thheller05:09:51

but that is not necessary if you don't need it

thheller05:09:11

in case of the npx shadow-cljs node-repl all it does it connect to the socket REPL (also provided by server) and eval (shadow.cljs.devtools.api/node-repl), which again just switches that connection to CLJS