Fork me on GitHub
#hyperfiddle
<
2023-09-22
>
nivekuil03:09:35

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 text

🙏 1
nivekuil03:09:37

same with style, setting (.-style dom/node) directly works but not through dom/props

1
Dustin Getz10:09:52

assuming your diagnosis is correct i can infer what is happening:

Dustin Getz10:09:24

electric on unmount will run cleanup effects in reverse order of mount effects

Dustin Getz10:09:18

so dom/text is disposed, and then dom/div is disposed, and these are distinct

Dustin Getz10:09:14

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

Dustin Getz10:09:20

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

Dustin Getz10:09:33

so it restores the just-emptied div

Dustin Getz10:09:44

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

Dustin Getz10:09:54

we recognize that animation is important

nivekuil17:09:13

there needs to be a way to signal to the cleanup handler "wait, not yet" as a mount effect

nivekuil17:09:07

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

👀 1
nivekuil20:09:02

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

Dustin Getz00:09:24

there are edge cases, like a div with N text nodes managed by e/for

Dustin Getz00:09:30

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

Dustin Getz00:09:27

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

nivekuil00:09:51

problematic in general yes, but for text/props?

Dustin Getz00:09:40

we have not thought about it yet, you’re the first to report this problem

Dustin Getz00:09:10

doesn’t the animation problem also include non trivial cases like a div needing to be retained with complex children?

nivekuil00:09:38

not sure, it works with other vdomless frameworks like svelte.. do they do cleanup logic differently

Dustin Getz00:09:12

wrt inhibiting cancellation missionary has a primitive for that i believe - m/compel it might solve your problem

Dustin Getz00:09:47

cancellation is “best effort” so as to return synchronously

nivekuil00:09:08

the thing I need to compel is somewhere in r/hook and idk what i'm reading

Dustin Getz00:09:56

i was thinking something like (new (m/compel (e/fn [] (dom/div …))) no idea how far this is or if it can work

wei07:09:48

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/050ee89c51d33a1a09997b7b51b346a8

xificurC08:09:35

can 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?

grounded_sage08:09:20

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.

🙏 1
grounded_sage08:09:20

I just used an atom because I haven’t learnt missionary properly yet

xificurC09:09:02

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

wei15:09:21

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

wei15:09:38

i'm like grounded_sage, currently using atoms everywhere

Dustin Getz15:09:07

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

🙏 1
Dustin Getz15:09:28

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

wei15:09:10

do you have any examples of accumulating with missionary (i think you end up with a flow), and consuming the flow with electric?

Dustin Getz16:09:07

here's one from today:

Dustin Getz16:09:02

mx is [contrib.missionary-contrib :as mx]

Dustin Getz16:09:16

which is bundled with electric, sorry for the bad name it's a todo to fix that

xificurC16:09:50

@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

wei16:09:39

thank you both! will try

Dustin Getz16:09:20

Keyboard state example

👍 2
❤️ 1
👀 1
Dustin Getz16:09:29

by @U0ETXRFEW and me this morning

pez16:09:09

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

Dustin Getz16:09:13

i edited the node argument passing to remove the inconsistency here

Dustin Getz16:09:47

mix here is using the secondary arity of m/?> to specify parallelism factor, such that all the flows race

pez16:09:46

Ah, yes, I see it now!

bherrmann19:09:06

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.

🙂 1
yes 1
Dustin Getz20:09:20

yes, Electric is built in service of Hyperfiddle, which is a programmable crud spreadsheet

Dustin Getz20:09:14

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

Dustin Getz20:09:25

Electric v3 (Differential Electric) is the solution and encompasses all these learnings

🚀 5
J21:09:43

Little multiplayer quiz app with Clojure, Electric and Rama

❤️ 12
joshcho04:09:33

@UHZPYLPU1 in ur experience, how much complexity does rama add to the code? vs vanilla electric

henrik06:09:15

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.

❤️ 1
J06:09:16

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

❤️ 1
danielstockton11:09:05

@UHZPYLPU1 Are you planning to make the code available? I'd be interested to see how it works.

J12:09:39

I need to polish some parts and maybe rewrite it with the plain Clojure api

danielstockton13:09:15

Is the plain Clojure api for rama now documented/available?

J14:09:19

Not yet. I use the Java api

👍 2
grounded_sage23:09:59

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?

Dustin Getz23:09:54

straightforward, have a look at how the entrypoint works. Perhaps start with the unit test entrypoint which has no websocket

Dustin Getz23:09:49

a related harder issue is support for “N sites” not just client/server. It’s hardcoded to 2 currently

grounded_sage23:09:58

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.

Vincent06:09:25

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.

grounded_sage07:09:53

I’m bundling it into a native app for distribution to Mac, windows, Linux

🙌 1
grounded_sage07:09:32

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.

🙂 1