This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2024-01-30
Channels
- # announcements (5)
- # babashka (2)
- # beginners (85)
- # cider (59)
- # cljs-dev (2)
- # clojure (10)
- # clojure-europe (61)
- # clojure-gamedev (20)
- # clojure-nl (2)
- # clojure-norway (9)
- # clojure-uk (5)
- # cursive (24)
- # data-science (4)
- # datascript (8)
- # emacs (1)
- # fulcro (8)
- # graalvm (30)
- # gratitude (9)
- # hyperfiddle (71)
- # introduce-yourself (1)
- # jackdaw (1)
- # leiningen (8)
- # london-clojurians (1)
- # missionary (3)
- # other-languages (10)
- # pathom (8)
- # pedestal (18)
- # polylith (4)
- # proletarian (5)
- # reitit (7)
- # releases (4)
- # ring (8)
- # sci (10)
- # shadow-cljs (27)
- # squint (3)
- # tools-deps (2)
- # xtdb (17)
Hello!
I've been trying to run this gist https://gist.github.com/dustingetz/1960436eb4044f65ddfcfce3ee0641b7
The second snippet with the !dirty gets me unbound electric var
electric-starter-app.main/!dirty`, did I somehow manage to break something is so few lines or is the snippet not working? If so what is happening exactly? does binding not "see" previous bindings in the same form?
It looks like there’s a mistake in the snippet. Sorry.
binding
binds in parallel (in both Electric and Clojure).
Until we revise the snippet, you can try with:
(binding [!dirty (atom 0)]
(binding [dirty (e/watch !dirty)]
...)
ok thanks!
Do you still use something like mount with electric to manage eg database connections that need to be closed?
No need, Electric has the mount/unmount lifecycle baked in.
(e/defn GetDbConn []
(let [my-closable-conn (get-db)]
(e/on-unmount #(.close my-closable-conn))
my-closable-conn))
I get
ERROR hyperfiddle.electric: #error {
:cause Wrong number of args (0) passed to: hyperfiddle.electric.impl.runtime/constant/fn--7241
...
in dynamically bound ( electric-starter-app.main/GetDbConn )
In a binding like this:
(binding [pg-conn (GetDbConn)] ... )
Electric functions (`e/defn` and e/fn
) are called with new
: (new GetDbConn)
or the equivalent (GetDbConn.)
.
Ah thanks! but how does it work for e/fn then, eg in that snippet:
(CodeMirror. {:parent dom/node}
(e/fn [x]
(try (edn/read-string x)
(e/server (reset! !sql-map x))
(catch #?(:clj Throwable :cljs :default) t
nil))
x)
contrib.str/pprint-str
(e/server sql-map))
I suppose that is why I get "#object[TypeError TypeError: n.call is not a function]"I don’t see anything wrong with this snippet.
e/fn
is called like e/defn
:
(let [Identity (e/fn [x] x)]
(new Identity 1))
or shorter: (new (e/fn [x] x) 1)
I think what is wrong is that the code mirror expects a clojure/script write-fn, but then you can't have e/server in it?
a cljs fn and an electric fn are 2 distinct objects. If you are interoperating with a js library that expects a (cl)js fn you cannot pass it an electric fn. Are you trying to use our contrib codemirror namespace?
I'm trying to update the value on the server when the content changes
event just that fails:
(CodeMirror. {:parent dom/node}
(e/fn [x]
x)
identity
@!input)
#object[TypeError TypeError: n.call is not a function]
```it's from the contribs: [contrib.electric-codemirror :as codemirror :refer [CodeMirror]]
I'm trying to update the value in the server when the content changes
(e/defn GetDbConn []
(let [my-closable-conn (get-db)]
(e/on-unmount #(.close my-closable-conn))
my-closable-conn))
wouldn't that open/close the connection for every client? if I'm using a connection pool I wouldn't want that?Depends on what get-db
does. If it acquires the connection from a pool or if it builds a fresh one.
yeah in my case it creates the connection pool:
(jdbc.connection/->pool
HikariDataSource
{:minimum-idle 10
:maximum-pool-size 10
:username "user"
:password "password"
:driverClassName "org.postgresql.Driver"
:jdbcUrl "jdbc:"})
for people who have experimented with rich text editors in electric, which libraries did you use?
i've gotten vanilla lexical to work with a lot of hacking. maybe if i used react lexical the integration would have been simpler.
Off topic, but wondering if you've used ProseMirror and how you would compare it to Lexical @U066TMAKS? (Unrelated to Electric)
I think it's so cool we can do this now
(e/defn Main [ring-request]
(e/server
(binding [e/http-request ring-request]
(e/client
(binding [dom/node js/document.body]
(ShompMain.))))))
i figured out how to do it from the extended chat demo, which may or may not exist somewhere currently
Yes extended chat demo reads cookies. It is in the electric-tutorial
fiddle.
I observe a strange behaviour with e/for-by iteration over a collection, where multiple dom nodes are created in each iteration step. When a item in the middle of the collection gets removed, then the ui gets cluttered. Is this behaviour expected? (i paste an example with screenshots in the comments)
(def !my-list (atom [1 2 3 4 5 6]))
(e/defn Entry [text]
(e/client
(e/on-unmount #(println "unmount" text))
;no single containing dom element
(dom/div
(dom/text text))
(dom/div
(dom/text "Foo"))))
(e/defn List []
(e/server
(let [my-list (e/watch !my-list)]
(e/for-by identity [v my-list]
(e/client
(Entry. v))))))
(comment
(reset! !my-list [1 2 4 5 6]); remove from the middle
)
i recently had some strange behavior around conditionals causing client/server mismatches, maybe check for that? https://clojurians.slack.com/archives/C7Q9GSHFV/p1706249048037089
Thanks for that hint. I carefully checked, that I do conditional requiring of namespaces that contain electric definitions. But I still get the strange behaviour. btw I am using electric version “v2-alpha-540-ga4699532”. Did you try to reproduce with the same?
it's the conditionals that cause the undefined behavior. e/defs
need to be defined on both the server and the client (no conditionals) and there's currently no warning if one side is missing
I stil get the error with latest master. I only get corret behaviour, if I wrap each iteration step in another div like so
(dom/div (Entry. v))
how about try to repro on a clean clone of electric-starter-app
or electric-fiddle
? that would tell you if it's an issue with your specific app
I testet with the electric fiddle repo and extended the hello fiddle:
#?(:clj (def !my-list (atom [1 2 3 4 5 6])))
(e/defn Entry [text]
(e/client
(e/on-unmount #(println "unmount" text))
;no single containing dom element
(dom/div
(dom/text text))
(dom/div
(dom/text "Foo"))))
(e/defn List2 []
(e/client
(dom/div
(e/server
(let [my-list (e/watch !my-list)]
(e/for-by identity [v my-list]
(e/client
(Entry. v))))))))
(comment
(reset! !my-list [1 2 4 5 6]); remove from the middle
)
(e/defn Hello []
(e/client
(List2.)
(dom/h1 (dom/text "Hello world"))))
I still get the wrong behaviour (see screenshot). @U09K620SG do you have any idea what could cause this behaviour?I also suspect (like Wei) some sort of desync. The recent Electric incremental compilation changes made it easier to desync the frontend and backend using things like reader conditionals to cause the client and server to see different programs, we're still gathering info
It could also be a bug, the IC changeset was huge
i'm mounting/unmounting a table of 100 form 1-2s delay. any suggestions for making this more performant? I also tried commenting out the input elements (keeping the row divs) and while it's better, there's still some delay. what's the overhead for ui4/input
elements inside an e/for-by
when the user switches tabs, and there's a e/defn
and should i be trying to inline things here?
yeah e/fn overhead is high in v2, and worse, each electric-dom2 container (div, tr, etc) has a hidden e/fn wrapping the children. Really new
is what has the overhead and in electric-dom2, new is everywhere. This is a top dev priority, Electric v3 will be better due to resolving a bunch of technical debt (Spring release) and one consequence of Electric v3 is that all of the hidden e/fns inside dom containers are no longer needed, which might solve this issue outright
Yes there are optimizations you can do in the meantime – i'll get back to you, i'll make a short list
thanks! i can also wait for v3 if the optimizations are v2-specific. targeting a late spring release for this particular project
Can you copy paste the key parts of your code into a gist? DM me if you want to keep it private
um, i'm not sure. Both involve new
do you have a lot of them?
maybe a dozen? not as many as i have inputs and defns. i'll treat them the same in terms of cost then
To follow up in public, step 1 is virtualized scroll, demo here: https://electric-datomic-viewer.fly.dev/(:app.datomic-browser!attribute,:abstract%52elease!name)
However, even in that demo, navigating between tabs is not instant, it's maybe 300ms to switch tabs (though not 1-2s). Some of this can be blamed on network delay but there is also clearly a waterfall load of sorts happening because the cells stagger in if you look closely
if the backend queries for the query/cells are slow, due to the waterfall this can really explode out, that's when you really need to optimize today. Heavy electric-dom2 usage also adds weight due to it's internal e/fns as mentioned above.
Is electric-starter-app
intended to be maintained long-term as the clean starting point? I migrated to electric-fiddle
a few weeks ago — now it seems the sensible thing is to move back. Another question -- is there any reason not to keep the remote and repeatedly rebase on top of it? I like the idea of automatically updating dependencies and so on.
honestly we don't commit to anything, we're still triangulating what our requirements are and what user requirements are. electric-fiddle is intended to have "batteries included" and electric-starter-app is intended to document the cleanest possible entrypoint because electric-fiddle has extra complexity (due to so many apps co-existing each with its own classpath requirements)
the reality is that your app http middlewares (auth and such) are customized in 100% of real apps, so you have no choice but to understand the 100 line example http entrypoint
OK, I'll stick with electric-fiddle for now, and yes I've been putting off understanding the underlying parts properly but I'll have to figure it all out one day!
I'll add that electric-fiddle is far too fiddley today, it was shipped quickly and we're working on ways to improve it
That's true! I would probably get less conflicts on electric-starter-app. Thanks for the guidance as ever 🙂 Looking forward to the Differential talk
(e/defn GetDbConn []
(let [my-closable-conn (get-db)]
(e/on-unmount #(.close my-closable-conn))
my-closable-conn))
wouldn't that open/close the connection for every client? if I'm using a connection pool I wouldn't want that?