This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-09-22
Channels
- # babashka (106)
- # beginners (29)
- # biff (29)
- # calva (9)
- # cider (6)
- # clj-kondo (24)
- # clojure (40)
- # clojure-europe (94)
- # clojure-japan (1)
- # clojure-nl (1)
- # clojure-norway (45)
- # clojure-uk (13)
- # clojuredesign-podcast (5)
- # clojurescript (12)
- # clr (4)
- # community-development (2)
- # conjure (13)
- # cryogen (4)
- # cursive (4)
- # deps-new (1)
- # fulcro (18)
- # hugsql (2)
- # hyperfiddle (67)
- # jobs (1)
- # malli (47)
- # meander (2)
- # missionary (34)
- # off-topic (1)
- # podcasts-discuss (1)
- # polylith (24)
- # reagent (19)
- # reitit (9)
- # sci (7)
- # shadow-cljs (3)
- # testing (28)
- # tools-deps (1)
- # xtdb (9)
with https://github.com/formkit/auto-animate, text doesn't animate on unmount with dom/text
. there seems to be a surprising difference in behavior:
(set! (.-textContent dom/node) "this works")
(dom/text "this doesn't")
from what I can tell the way the library works is it keeps track of elements to animate, and when one disappears, it recreates it to animate its removal. but with dom/text
the recreation does not have any textsame with style, setting (.-style dom/node)
directly works but not through dom/props
assuming your diagnosis is correct i can infer what is happening:
electric on unmount will run cleanup effects in reverse order of mount effects
so dom/text is disposed, and then dom/div is disposed, and these are distinct
the set! workaround does not have a cleanup handler, so is not cleaned up, it leaves the text behind (leaks resource) but gets away with it because it is an encapsulated component of dom/div and will be deleted as part of the dom/div
the library is detecting the dom/div removal and restoring it to its former state, but this detection happens AFTER the dom/test was disposed as those are distinct resources in electric
so it restores the just-emptied div
think about it and let me know what you think we should do, i am resistant to the idea of degrading electric’s RAII semantics for this library to work, would first want to analyze the problem carefully and survey the ecosystem for ideas
we recognize that animation is important
there needs to be a way to signal to the cleanup handler "wait, not yet" as a mount effect
that is necessary for animation in general. With this lib you could get ahead of the cleanup handler to delete the parent div first, and hopefully that doesn't break the default electric cleanup handlers
why bother cleaning up things like that in the first place though? isn't set! the more straightforward implementation, and probably faster if you let the browser clean up children
there are edge cases, like a div with N text nodes managed by e/for
another edge case is a dom/div with dom/props, and then another dom/props overriding the first dom/props, but the inner one is blinking in and out on a timer. we currently don’t support that and it’s a problem
the problem being, when unwinding the inner effect how to restore the action of the outer effect, you have to run it again which is problematic
we have not thought about it yet, you’re the first to report this problem
doesn’t the animation problem also include non trivial cases like a div needing to be retained with complex children?
not sure, it works with other vdomless frameworks like svelte.. do they do cleanup logic differently
wrt inhibiting cancellation missionary has a primitive for that i believe - m/compel it might solve your problem
cancellation is “best effort” so as to return synchronously
i was thinking something like (new (m/compel (e/fn [] (dom/div …))) no idea how far this is or if it can work
how would I take a core.async channel of tokens and display the tokens as they come in, like how chatgpt's website streams its responses? i can consume the channel like this:
(let [events (chat-streaming params)]
(go
(loop []
(when-let [event (<! events)]
(if (= (:status event) :done)
(info "Stream ended with DONE token.")
(do
(info "Received event:" event)
(recur)))))))
do I convert the channel into a missionary flow and hook that up to a div? not quite sure how to put that together in practice.
here's the server-side bit btw, with example of consuming the channel:
https://gist.github.com/yayitswei/050ee89c51d33a1a09997b7b51b346a8can you cut the middleman and use missionary directly? What would you like to do with the data concretely? Just set innerText of an element or build nodes?
I’ll send you a dm. I have a big repo doing a chatbot I just open sourced I’m just preparing an announcement and making sure it’s working because it’s tracking upstream work.
I just used an atom because I haven’t learnt missionary properly yet
your chat-streaming
fn could use missionary at which point the integration gets simpler. For cases where you don't control the code and you get a core.async channel we have https://github.com/hyperfiddle/electric/blob/master/src/contrib/missionary_core_async.cljc
@U09FL65DK yes, i'd like to apply a transform (extract the text from a json) and set the innertext of an element. assuming i can use missionary, what would the chat-streaming function look like and how can i consume it?
I think you need state, you can use either an atom to accumulate the response for rendering or you can use a missionary flow reduction to do the same thing. Electric v3 (Differential Electric) has native support for streaming APIs but no ETA yet
I recommend accumulating with missionary (on the server) and then bridging to electric with new
on the server, then start your e/for-by on the server and switch to the client for the branches of the e/for to render a table
do you have any examples of accumulating with missionary (i think you end up with a flow), and consuming the flow with electric?
here's one from today:
mx is [contrib.missionary-contrib :as mx]
which is bundled with electric, sorry for the bad name it's a todo to fix that
@U066TMAKS here's an untested translation of your function. I'm not sure if the http post call and .read
block, if some of them don't you can remove the m/via
. The function returns a missionary flow of parsed events
by @U0ETXRFEW and me this morning
Mostly Dustin 😃 Very fun. Though I think I’ve already forgotten what I was taught about that mix
function. My mind goes 🤯 when trying to understand. A thing to watch out for here is that dom/Focused?
implicitly works on dom/node
, whereas the keyboard-state<
flow is explicit about it. You might want to roll a version of dom/Focused?
with a second arity (or maybe just one arity and be explicit about what is focused).
i edited the node
argument passing to remove the inconsistency here
mix
here is using the secondary arity of m/?>
to specify parallelism factor, such that all the flows race
Huh, can "Electric Clojure" be thought of as a spreadsheet spread across multiple running environments. Where cells can present as HTML, or generate data, or sink data. I guess this is a duh, as hyperfiddle was even more spreadsheet-like. But thinking about "Electric Clojure" as being able to model a spreadsheet is interesting... and easier to explain to others... where as explaining that computation flows from the backend to the frontend and visa versa, is harder to think about.. but thinking about a column of cells being summed - that's easier to grasp.

yes, Electric is built in service of Hyperfiddle, which is a programmable crud spreadsheet
Hyperfiddle still exists! It is just blocked on Electric being "finished", our prototypes have some performance issues that require electric's managed network to be essentially perfect – very tight operational tolerances
Electric v3 (Differential Electric) is the solution and encompasses all these learnings
excellent!
@UHZPYLPU1 in ur experience, how much complexity does rama add to the code? vs vanilla electric
Not the author, but my opinion is that Rama doesn’t add complexity exactly, but it does force you to think about concerns related to scalability up-front, which you might have ignored for a PoC/spike/toy app. Partitioning, for example.
@U6D1FU8F2 Rama doesn’t add complexity. It’s a new different way to handle your backend like receive data, transform data and store data. I dream the Clojure API ^^ but the Java api do the job for now. For now I use the InProcessCluster, I don’t have access to the beta 😢 . The combination with electric is very impressive. It’s so easy to build reactive app. The reactive query of Rama is also very cool.
@UHZPYLPU1 Are you planning to make the code available? I'd be interested to see how it works.
Is the plain Clojure api for rama now documented/available?
How difficult both now and the trajectory of work in electric would it be to use IPC for say Electron or Tauri instead of a server with websockets?
straightforward, have a look at how the entrypoint works. Perhaps start with the unit test entrypoint which has no websocket
a related harder issue is support for “N sites” not just client/server. It’s hardcoded to 2 currently
Cool. This is good to know. I just realised the extent of the firewall and security concerns with spinning up a server. Probably going to be experimenting a lot in-house before making any serious decisions because I’m curious about joining data across many sources. Peer to peer data on local network and also remotely. But also need to not let scope creep without sufficient benefits.
methinks: ubuntu+nginx+dns_settings is enough for a secure setup. you can use SSL via let's-encrypt for free. it's not zero-think but it can be relatively zero-tink for a secure server for an application or several.
I watched your London meet talk and saw you mention site switching, extra sites, as something that could be built with more funding. That would be awesome in the future.