squint

zachcp 2025-05-06T18:45:48.806379Z

Small code org question for the squint repo. I really like the simplicity of your squint playground and was going to fork/copy it. After looking at the code I notice that there is the squint.edn , vite and other config file but that none of them seem to be used or necessary and that most of the commits are directly against the public/js/main_js.mjs as opposed to the cljs file. I suppose I was wondering which direction you evolving towards - e.g. total use of js in MJS or a squint compilation step before loading.

zachcp 2025-05-06T18:46:14.951859Z

code link here https://github.com/squint-cljs/squint/tree/main/playground

zachcp 2025-05-06T18:47:27.863129Z

( Also if you are def heading one way or the other I'd be happy to work on it )

borkdude 2025-05-06T19:39:41.743199Z

I think the .mjs code started small and then grew out of proportion ;)

borkdude 2025-05-06T19:40:03.174319Z

next time I'd start in squint probably, but it's kind of done now

👍 1
m3tti 2025-05-06T21:19:06.947499Z

hey guys i played around with snabbdom cause i was thinking about building a framework around this virtual dom implementation due to the fact that it only does the rendering part nothing more. And i was curious if i could it working with squint and jsx syntax and what should i say it works like a charm. So here is a little gist if you would be interested in how it would work for you https://gist.github.com/m3tti/7d5bf262b952df4f9059c772ea361449

👍 1
🎉 4
m3tti 2025-05-07T13:05:11.534679Z

@borkdude somehow snabbdom uses the props to transfere classnames do you know if it would be possible for the #jsx meta to produce something like that i'm currently figuring out why it does that but this look ugly if you use it with hiccup style 😄

(render (js/document.getElementById "app")
        #jsx [:div {:props {:className "reveal"}}
              [:div {:props {:className "slides"}}
               [:section "Hello"]
               [:section "World"]]])

borkdude 2025-05-07T13:06:34.089169Z

in squint JSX you can write [:div.reveal ...] to generate a class on the JSX, but I don't know why snabbdom expects it in a different way?

m3tti 2025-05-07T13:07:14.965849Z

yeah i'm currntly trying to figure it out i was thinking about leveraging it to create something like the elm architecture but for squint 😄

m3tti 2025-05-07T13:07:55.202879Z

i guess i can write a helper function to traverse the vector on my own and generate the stuff but you know i'm lazy 😄

m3tti 2025-05-07T13:08:32.786369Z

but than if i do it you don't even need to transpile the jsx 🤔

borkdude 2025-05-07T13:28:52.150999Z

perhaps their "just use a function to produce a dom node" isn't too bad?

m3tti 2025-05-07T13:29:57.884579Z

yeah i'm working on something where you can still paste "hiccupy" syntax and it produces the functions

m3tti 2025-05-07T13:30:06.165469Z

or better calls the functions

m3tti 2025-05-07T13:37:53.963319Z

cause you have to use the newly created vnode with patch

m3tti 2025-05-07T13:38:08.807079Z

so patch gives you a new vnode and this has to be used in the next patch

borkdude 2025-05-07T13:38:50.019819Z

aren't I passing the new vnode?

borkdude 2025-05-07T13:39:39.834999Z

oooh like that

m3tti 2025-05-07T13:39:40.019469Z

one way or

borkdude 2025-05-07T13:39:41.262619Z

thanks

borkdude 2025-05-07T13:40:41.230169Z

👍

m3tti 2025-05-07T13:40:59.842379Z

so in general the idea afaik 😄 is that you define the new dom and use patch create the new dom and than overwrite it as soon as you want to do something

borkdude 2025-05-07T13:41:19.398169Z

makes sense

m3tti 2025-05-07T13:41:21.822399Z

i like it cause i'm a simple man and now you are free to create something on your own 😄 and the dom patching is done for you

m3tti 2025-05-07T13:41:46.457209Z

there is even a repo that has the elm architecture allready but i don't like it 😄 cause its not clojuresq enough 😄

m3tti 2025-05-07T13:42:19.556569Z

i would like to use atoms and build something with that and messages so basically just keywords that trigger functions (maybe?)

borkdude 2025-05-07T13:43:31.482199Z

yeah

m3tti 2025-05-07T13:43:36.066689Z

btw before that i'm playing with reveal js 😄

m3tti 2025-05-07T13:43:55.424589Z

and snabbdom 😄 would be cool to have something like defslide and drop some html code there

borkdude 2025-05-07T13:44:18.704129Z

so you can do a talk on borkweb or squint? ;)

m3tti 2025-05-07T13:44:39.002709Z

exactly if i'm once that proficient that i have something to tell thats at least as interesting as stuff you do

borkdude 2025-05-07T13:45:19.228399Z

I heard a podcast about htmx and they talked about a library called "morph" or something. Are you familiar with it?

m3tti 2025-05-07T13:45:32.839409Z

NOT YET 😉

m3tti 2025-05-07T13:46:35.505089Z

this one https://github.com/bigskysoftware/idiomorph

borkdude 2025-05-07T13:47:01.158809Z

right

borkdude 2025-05-07T13:47:08.000089Z

and datastar must be using something like that too

m3tti 2025-05-07T13:47:36.327859Z

yeah datastar look pretty cool but had to little time lately to really look into it but it looks quite promising

m3tti 2025-05-07T13:48:54.857869Z

OK

Idiomorph.morph(existingNode, "<div>New Content</div>");
that looks cool i guess the #html can be handy here

borkdude 2025-05-07T13:49:52.700799Z

one of the datastar authors is also in here: https://clojurians.slack.com/archives/C03U8L2NXNC/p1745366662164029?thread_ts=1740906547.043039&amp;cid=C03U8L2NXNC

m3tti 2025-05-07T13:51:19.644329Z

borkweb is still my number one thing i want to get better but after playing also a lot with bun and squint i'm also looking into something for clojurescript. I was inspired by #defnpodcast where they talked once that clojure is settled on react and that there is nothing "clojure native" for spas so why not trying to build something 😄

borkdude 2025-05-07T13:53:16.085379Z

#replicant is AFAIK react-free and works kinda like react, but not exactly sure. the author @christian767 has also been on several podcasts

borkdude 2025-05-07T13:54:55.353479Z

oh he mentions snabbdom in the README: > https://github.com/snabbdom taught me that components are not a necessary feature of a virtual DOM renderer. Life-cycle hooks can just as easily be attached to DOM nodes.

cjohansen 2025-05-07T13:56:17.265209Z

Yes, I made https://github.com/cjohansen/dumdom before I made Replicant. Dumdom is based on snabbdom. I wrote Replicant because I wanted something pure Clojure(Script) 🙂

m3tti 2025-05-07T13:56:37.932409Z

cool so in general its the same idea as far as i see

m3tti 2025-05-07T13:57:00.007139Z

which is really cool cause the rendering is one part but the architecture and updating mechanism is another

cjohansen 2025-05-07T13:57:42.615279Z

Replicant is roughly "React in ClojureScript", except it only does rendering, and does not allow component-local state. I wrote kind of a lot about it at https://replicant.fun 😅

borkdude 2025-05-07T14:01:04.613119Z

@christian767 I must admit that I've listened to at least one or more podcasts about replicant, but I still can't remember how replicant does efficient updates to the dom

cjohansen 2025-05-07T14:02:08.503179Z

It basically implements a vdom-style diffing algorithm

cjohansen 2025-05-07T14:02:38.492669Z

It stores a representation of the rendered DOM, and on the next render, it diffs your hiccup against what's already rendered

borkdude 2025-05-07T14:03:10.161799Z

so closer to snabbdom than the idiomorph stuff

cjohansen 2025-05-07T14:03:34.792709Z

Probably - given that I know nothing about idiomorph 😅

borkdude 2025-05-07T14:03:56.199079Z

we discussed it briefly above. idiomorph doesn't use vdom, just direct dom

borkdude 2025-05-07T14:04:08.103049Z

it's part of htmx

cjohansen 2025-05-07T14:04:13.438479Z

Aha, I see

cjohansen 2025-05-07T14:04:27.852669Z

You're right then 🙂

borkdude 2025-05-07T14:04:48.749599Z

Thanks for coming all the way to this channel btw :)

cjohansen 2025-05-07T14:05:09.113959Z

You summoned me, of course I show up 😄

👻 1
m3tti 2025-05-07T14:06:33.364199Z

thank you @christian767 for clarifying and showing up 😄

borkdude 2025-05-07T14:06:38.677479Z

shadow-cljs also has something "native" right? are you aware of this and does it use a similar approach?

cjohansen 2025-05-07T14:07:38.682529Z

Yes, https://github.com/thheller/shadow-grove is an even more true "Clojure-native React". I wasn't aware of it when I started working on Replicant.

cjohansen 2025-05-07T14:08:02.110469Z

I think shadow-grove basically supports all of what React supports, while Replicant is more narrow and opinionated.

borkdude 2025-05-07T14:08:57.921519Z

and replicant has a better marketing department :)

cjohansen 2025-05-07T14:09:07.512619Z

Hehe 😄

cjohansen 2025-05-07T14:09:48.163769Z

I suspect shadow-grove has actively not been marketed

cjohansen 2025-05-07T14:12:39.731719Z

The marketing will continue until morale improves!

borkdude 2025-05-07T14:13:17.000779Z

Yes, keep going with it, you're doing a great job :)

❤️ 1
cjohansen 2025-05-07T14:13:58.124049Z

Thanks 😊

m3tti 2025-05-07T14:16:34.541399Z

so one simple question 😄 how hard would it be to transfere replicant to squint 😄

cjohansen 2025-05-07T14:17:45.390839Z

I don't know enough about Squint to answer that, but the code is just cljc without any dependencies, if that helps.

m3tti 2025-05-07T14:18:18.880639Z

he that would mean it could just work right @borkdude

borkdude 2025-05-07T14:19:01.778339Z

Replicant can just run in ClojureScript alone right? without any server component. Perhaps it's possible to transfer it to squint then, although data structures in squint are just JS data structures, no immutable collection like CLJS. I guess that would break things, since you can't easily diff them like in CLJS?

borkdude 2025-05-07T14:19:18.838089Z

Maybe put it another way: if you would rewrite replicant in pure JS, would there be any challenges?

cjohansen 2025-05-07T14:21:19.707859Z

Replicant runs fine in ClojureScript, no server needed. But yes, it does rely quite a bit on comparing data structures.

cjohansen 2025-05-07T14:22:05.856189Z

If it can't diff compare data, it will end up doing more work than necessary, but it should still technically work. It might get very slow.

borkdude 2025-05-07T14:22:37.024589Z

I mean, (= data1 data2) doesn't work like you'd expect from CLJS in squint

borkdude 2025-05-07T14:22:55.999319Z

you could use immutable.js for this but that would maybe defeat the purpose

borkdude 2025-05-07T14:23:09.920699Z

right

Delaney Gillilan 2025-05-10T21:58:16.722989Z

Yeah, I lurk... if you have any D* questions happy to answer

👋 1
Delaney Gillilan 2025-05-10T21:59:30.806159Z

I've been thinking alot about being used for webcomponents lately

Delaney Gillilan 2025-05-10T22:03:36.436389Z

So yes we started with idiomorph, in fact it's been the default since the first commit. However we've worked with the Turbo guys and thoses that have taken over the idiomorph. In the v1 coming out soon we have our on version that's about 60% smaller and about 3.5x faster.

🎉 3
zachcp 2025-05-06T00:20:07.430419Z

Stuck on macros. Looks like my compiled macro namespace retains fns from clojure core. I would appreciate any pointers/examples.

git clone 
cd squint-mol
npm i
npx squint compile
node dist/mvsj/tests.mjs
squint-mol % node dist/mvsj/tests.mjs
file:///Users/zcpowers/Downloads/squint-mol/dist/mvsj/core.mjs:33
const G__209 = ({ "kind": clojure.core.name(name176) });
                          ^
ReferenceError: clojure is not defined

borkdude 2025-05-06T08:27:15.753079Z

re: (mapv nodize ~children-sym) you can't use a macro as a higher order function, it must always appear in call position

borkdude 2025-05-06T08:28:24.928009Z

but if you can do it with a function, even better

zachcp 2025-05-06T00:25:30.515799Z

I'm going to try a few simple macros first. One issue I have is that I amtrying to be recursive (see nodize on last line ) :

(defmacro nodize
  "Transforms a hiccup-like vector [:name props children] into a node map."
  [form]
  (let [name-sym (gensym "name")
        props-sym (gensym "props")
        children-sym (gensym "children")]
    `(let [[~name-sym ~props-sym ~children-sym] ~form]
       (cond-> {"kind" (name ~name-sym)}
         (not (empty? ~props-sym)) (assoc "params" ~props-sym)
         (seq ~children-sym) (assoc "children" (mapv nodize ~children-sym))))))

zachcp 2025-05-06T00:27:46.827929Z

also thinking this can be a fn which makes the compilation simpler...

zachcp 2025-05-06T00:53:11.405279Z

fns to the rescue: Okay this is simple and works great. back the main project! 🙂

(defn nodize
  "Transforms a hiccup-like vector [:name props children] into a node map."
  [form]
  (let [[name-val props-val children-val] form]
    (cond-> {"kind" name-val}
      (not (empty? props-val)) (assoc "params" props-val)
      (seq children-val) (assoc "children" (mapv nodize children-val)))))

            [mvsj.macros :refer [nodize]]))

(assert (=
         (str (nodize [:test {:param 1} []]))
         (str {:kind "test" :params {:param 1}})))

(assert (=
         (str (nodize [:test {:param 1} [[:test2 {:param 2}]]]))
         (str {:kind "test" :params {:param 1} :children [{:kind "test2" :params {:param 2}}]})))

🎉 1