This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-06-23
Channels
- # announcements (3)
- # aws (1)
- # beginners (44)
- # biff (6)
- # calva (31)
- # cider (26)
- # clerk (12)
- # clj-kondo (9)
- # clojure (17)
- # clojure-dev (18)
- # clojure-europe (13)
- # clojure-norway (45)
- # clojure-uk (4)
- # clojurescript (34)
- # datomic (54)
- # dev-tooling (14)
- # emacs (19)
- # events (7)
- # honeysql (2)
- # hyperfiddle (51)
- # lsp (34)
- # malli (24)
- # matrix (1)
- # missionary (5)
- # off-topic (27)
- # re-frame (6)
- # reagent (18)
- # releases (2)
- # sci (6)
- # shadow-cljs (88)
- # vim (9)
Is it possible to use electric without a backend server, only using the missionary-based reactive dom functions? I'm trying to create an SPA that connects directly to websockets that I don't control. Electric would be a great fit for this, since data is coming in incrementally.
you’ll need to write some missionary to “integrate” whatever events are coming over the websocket into an electric signal
we are working on a new primitive e/for-by-streaming that would be suitable for rendering an incremental table derived from a stream of messages, but it’s not going to land until late July
My plans for incremental rendering with the current e/for-by was (something like) (m/latest identity (m/reductions conj (sorted-set) my-flow))
I'll look into seeing if its possible to hack e/boot to not create a server part, and not try to connect to it. (Ideally, there wont be a server to connect to.)
or are you saying that e/boot wont try and connect to a server ws if e/server is never used?
This seems to work as a really hacky replacement for e/boot
that disregards any server and works without a backend to connect to, but I wont pretend to understand the macros enough to even really guess /why/ it works
(defmacro boot [& body]
(let [[client] (c/analyze
(assoc &env ::c/peers-config {::c/local :cljs ::c/remote :cljs})
`(e/with-zero-config-entrypoint ~@body))]
`(~(r/emit (gensym) client)
(m/rdv)
identity)))
sorry, yeah as Geoffrey said, i think the test entrypoints should do what you want
rather than send something via ajax, is it possible to place something onto a clj
channel from a cljs
channel? o_O
ajax feeling redundant and not working out of the boxs 😅 got me thinking, maybe leverage the socket, and maybe can put on channel?
If you are communicating with your own server, you should be able to just call whatever your http handler on the server is doing, directly from the client, inside a (e/server ,,,)
.
(d/defn MyComponent []
(e/client (e/server (async/put! a-channel a-val))))
haha hell yeah! that's what i'm talkin' about. okay i don't know much about channels at the moment but i reckon they ought be the thingy.
If by channel you mean a core.async channel, I would look into wrapping it into missionary tasks/flows (or just using missionary tasks/flows instead), since that will be much more directly compatible with electric. See https://github.com/leonoel/missionary/wiki/Basic-Walkthrough:-Tasks-&-Flows and https://github.com/leonoel/missionary/wiki/Task-interop#coreasync-channels
Yeah, any clojure value should work.
As long as it can get serialized on a websocket.
if you are just doing crud stuff you can write to the database in an e/server directly without any async stuff (unless the database client uses core async in which case we recommend you adapt it to missionary, we have adapters for that in the electric repo somewhere)
wrap blocking APIs with e/offload to move the call to a thread
the todos demo has a backend database
This seems to work as a really hacky replacement for e/boot
that disregards any server and works without a backend to connect to, but I wont pretend to understand the macros enough to even really guess /why/ it works
(defmacro boot [& body]
(let [[client] (c/analyze
(assoc &env ::c/peers-config {::c/local :cljs ::c/remote :cljs})
`(e/with-zero-config-entrypoint ~@body))]
`(~(r/emit (gensym) client)
(m/rdv)
identity)))
Any speculation on what optimistic updates might look like from a code pov in Electric in the future?
You will need to embrace our UI primitives (e.g. use ui/input
not dom/input
). The upcoming fifth UI design ui5
is callback-free, changes are represented as signals (e.g. an input control is an e/fn that returns a signal of the latest value of the input). There will be a few higher level Form/Field/List
components that process/merge these signals and also coordinate the merging of client and server information. At the application entrypoint (at the "top"), the Page will return a signal of requested (pending) edits (as a value) that the entrypoint should transact into whatever database. The view itself should remain fully composable - something like (Form. (div (Field. props (Checkbox.))) (div (Field. props (Input.)))
. I think it can be achieved, though the design is pushing Electric very hard and Electric will need some improvements to make it work
If the design succeeds — and i don't see any show-stopper risks after working on this for a few weeks — really you shouldn't care or notice any machinery related to optimistic state, it will "just work"
One specific tradeoff I'm fairly committed to is to make no attempt to run datalog/database stuff on the client. Any pending edits are considered view-local, not global. That is why there will be a List controller that can merge client state into a collection that came from the server in a very simple and local way – i.e., no database integrations to make pending records show up in queries globally across the client. (Is this what Fulcro does?)
(That said, you can imagine a future "Electric Datascript" with a network-transparent datalog engine and network-transparent indexes, which would put the whole problem of optimistic queries to rest permanently)
Also the UI5 controls know if they are "in sync" or not, so the application can render "sync dots" next to each control if desired (yellow->pending, red->rejected etc)
In theory, UI5 control state should survive network unplugs and resync when plugged back in, giving offline-mode capability. Note this is not quite offline-first, we merely wish to guarantee the safety of user state
@UCJCPTW8J was this what you are looking for? Some form of feedback would be appreciated so I can calibrate
Yeah no problem This is my use case: https://clojurians.slack.com/archives/C7Q9GSHFV/p1683796408377749?thread_ts=1683793979.145529&cid=C7Q9GSHFV I'm trying to recreate a bit of software called MindNode which isn't particularly novel besides the fact that all the interactions are high quality
I suppose the bit I'm interested in, is how readable or translatable will the optimistic update functionality of the new UI components be for what I'm trying to do Maybe I can try and use one of them directly, or try and reimplement them for my use case not sure yet
do you have business-level requirements listed you can share? E.g. a) locally optimistic, b) synced to server at least every 30ms, c) ... Or a complete user story. Real world use cases like this can help us sharpen the design as we work through the problem space
Well it's just for fun at the moment but this is the context of the original app: https://www.youtube.com/watch?v=urM77gmxnK8 This is an application that is local only at the moment, so the value add of doing it in electric is google docs style collaboration One of the first things I wanted to do was moving a "node" so you left click on a node, drag it and it mouse up to place it In the original application, the node moves with your mouse in real time as you drag it, so I wanted to implement that My priority is that the application moves the "node" as soon as the mouse event registers, then sends that position across the network when it is able to I care a lot about the current location of the node, but I don't mind if in-between mouse events are lost too much When I come to implement undo I'm not going to care about per pixel location but instead restore to checkpoint locations that will be marked with mouseup/down I don't know if that helps, it's kind of similar but not quite the same requirements as a multiplayer drawing app
I think the form-centric approach shares the exact same underlying utilities needed for syncing mouse signals
Syncing a mouse signal is much simpler actually, the approach used in UI4/input i think can be slightly modified to work for mouse signals
UI4 control implementation is complicated though, we aren't happy with the low level API at all, it was an early POC, we went with it in UI4 because it works and fixed problems
To answer the q directly: "how readable or translatable will the optimistic update functionality of the new UI components be for what I'm trying to do": the userland api should be perfectly readable
if i want to add an external cljs library to the front-end (like Stripe.js) is there a way i can add the javascript file more natively than loading it via html?
shadow-cljs understands node modules iirc, im a bit fuzzy on the details but you should be able to find info on clojure verse and searching other channels on this slack
chatGPT4 say there is a mystical deps.cljs
one can invent to add external js libs. am wondering if it same tactic
Always load Stripe.js directly from to remain PCI compliant. Do not include the script in a bundle or host a copy of it yourself.
:melting_face:it’s 100% ok to load by script tag, you might need to give clojurescript advanced mode a few hints if you care about that
Hey I finally got it to render 😄 I might have to make some instructional videos on un-learning conventional client/server comms
You can use the Stripe.js npm module, it will lazy load the JS script from their CDN. It will save you a split config and might help with advanced mode.