cljs-dev

dnolen 2025-06-10T12:58:17.718649Z

I guess all the cool kids are using brotli now, that does seem to give another 20% over gzip over here

Roman Liutikov 2025-06-10T15:18:18.974279Z

The coolest kids switched to zstd :D but yeah brotli is really good, 10mb cljs bundle outputs around 2.5mb

Roman Liutikov 2025-06-10T15:19:51.944329Z

JS generated from cljs seems to be very compression friendly, I assume because the same code gets generated for common forms

dnolen 2025-06-10T15:52:42.682669Z

yeah, it's very regular

dnolen 2025-06-10T16:58:44.661909Z

are there any ClojureScript native morphing libraries? I feel like this is something that would make ClojureScript a lot more useful out of the box w/o using random deps to get functional UI patterns

p-himik 2025-06-10T17:02:10.536719Z

To be honest, I'm not even sure what you're asking exactly. What's "morphing" in this context, especially given that we're in #cljs-dev and not #clojurescript?

dnolen 2025-06-10T17:05:41.376449Z

https://github.com/choojs/nanomorph

dnolen 2025-06-10T17:05:52.526439Z

https://github.com/patrick-steele-idem/morphdom

dnolen 2025-06-10T17:06:06.540489Z

https://github.com/bigskysoftware/idiomorph

dnolen 2025-06-10T17:07:41.763319Z

the last is the most robust wrt. DOM state (scroll position, input focus) etc. - it's not that big

dnolen 2025-06-10T17:10:54.240119Z

it's 2025, I think having a standard solution to this problem would be good to avoid taking on a dependency - hiccup also isn't going anywhere - it would be interesting to support both morphing DOM to DOM, but also Hiccup -> DOM - with special taken around DCE so you only pay for the strategy you use.

๐Ÿ‘ 1
p-himik 2025-06-10T17:12:06.614769Z

I think https://github.com/thheller/shadow-grove is relevant, at least it talks about DOM diffing, so maybe Thomas can chime in.

thheller 2025-06-10T17:12:31.050809Z

not a generic morph lib, also not hiccup. well the syntax yes, but not actual vectors and stuff in the end ๐Ÿ˜›

thheller 2025-06-10T17:15:37.369129Z

replicant exists if you can stomach the "interpreted hiccup" slowness. not that morph is fast by any means

thheller 2025-06-10T17:17:20.955199Z

not aware of anyone having implemented just morph in CLJS. kinda no point it those libs exists to go from DOM->DOM. hiccup is a different story, but if you are diffing that you might as well use replicant

dnolen 2025-06-10T17:24:56.366599Z

DOM->DOM could still be useful if you're doing an htmx / datastar style app like the Turbo example. I don't think that approach should be ruled out for CLJS. i.e. you have some CLJS that manages a a nice interactive component, but you don't want to deal w/ all this app state on the client.

thheller 2025-06-10T17:26:29.189979Z

idiomorph is one file. could probably just wrap that as a goog.module and go ๐Ÿ˜›

dnolen 2025-06-10T17:29:37.138059Z

yeah, no deps, very sensible - but I don't think it has alternate tree rep hooks?

dnolen 2025-06-10T17:30:29.925979Z

I'm thinking more along the lines of transit - so lower level thing just written in JS

dnolen 2025-06-10T17:31:34.243889Z

so DOM<->DOM is not adding much to the bundle - and then Hiccup bit on top of that

dnolen 2025-06-10T17:32:35.087409Z

and importantly, not really trying solve the more general problem of building apps - just a layer to support more functional DOM interactions

borkdude 2025-06-10T17:34:16.588649Z

replicant also has morphing and hiccup I think? I'll let @christian767 explain if he wants

cjohansen 2025-06-10T18:47:06.912159Z

It has hiccup, not entirely sure what morphing is. I have a feeling it's even more low level/barebones than Replicant?

cjohansen 2025-06-10T18:47:59.825639Z

Just looked at your example, and that looks a lot like what Replicant does, so maybe?

borkdude 2025-06-10T18:51:46.625179Z

morphing is just diffing and re-rendering the dom

borkdude 2025-06-10T18:51:48.715989Z

I think

cjohansen 2025-06-10T18:52:05.474529Z

In that case, yes, that's what replicant does ๐Ÿ˜Š

borkdude 2025-06-10T18:54:13.242109Z

I heard @mkvlr say in an interview that he would like to use replicant to make the "front end smaller" and "to do more on the server". Not sure if I understood well what he meant. I see replicant as a more functional way of managing state on the UI, but it's definitely not the same as HTMX where you render the HTML on the server and then send it to the client -- right?

cjohansen 2025-06-10T18:55:54.209299Z

No, it's not like HTMX. It's closer to something like "functional React". However, since it doesn't allow you to put any state management inside the rendering components, you're forced to do centralized state management. If you want to stick that part on the server and just render on the client that will work just fine.

cjohansen 2025-06-10T18:56:34.925829Z

Replicant doesn't really manage state, it just provides infrastructure for you to do it yourself.

borkdude 2025-06-10T18:56:53.865079Z

That's what I tell people who use my libraries as well. Just do it yourself man

borkdude 2025-06-10T18:57:07.279349Z

;)

cjohansen 2025-06-10T18:57:21.017819Z

๐Ÿ˜‚

cjohansen 2025-06-10T18:57:47.979659Z

Replicant is a rendering library

cjohansen 2025-06-10T18:57:54.508849Z

It does that for you

borkdude 2025-06-10T18:58:44.654049Z

yes, that's how I understood your presentation as well. Wondering what @mkvlr meant in the interview though

mkvlr 2025-06-10T19:36:06.214979Z

I meant the ability to render hiccup either to strings on the server or on the client, having the views in cljc files

๐Ÿ‘ 2
borkdude 2025-06-10T19:44:29.555349Z

If I've understood the talk correctly this is more for testing purposes than for keeping thing smaller?

mkvlr 2025-06-10T19:46:32.336269Z

I meant being able to render some views which donโ€™t need interactivity purely on the server to a string, while also supporting building a spa for parts that need it and sharing the view code for both

cjohansen 2025-06-10T19:47:59.663529Z

replicant.string can render static HTML just fine, we do that as well ๐Ÿ‘

cjohansen 2025-06-10T19:48:53.570089Z

I have also experimented with some HTMX-inspired stuff to allow static HTML rendered this way have event handlers. But I have too many ideas and projects and too little time ๐Ÿ˜…

cjohansen 2025-06-10T19:49:50.906979Z

@borkdude I didn't touch on this use of Replicant in the talk. Probably should have, but there's only so much one can do in 30mins.

borkdude 2025-06-10T19:51:55.930419Z

sure, but why not just use hiccup instead of replicant if you're going to do HTMX(-ish)?

cjohansen 2025-06-10T19:53:07.319989Z

Replicant supports some features not in hiccup, so if you're using Replicant on the client, its string renderer gives you the exact same semantics for the server.

cjohansen 2025-06-10T19:53:24.546589Z

If you're not using Replicant on the client at all, there probably is no point ๐Ÿ™‚

borkdude 2025-06-10T19:54:05.770099Z

right

cjohansen 2025-06-10T19:56:30.673399Z

The way we build our web app at work, we have a page abstraction with a render function. Its default mode is to render static HTML on the server. When we need more interactivity, we set :client-page? true and it runs render on the client instead. If the page also needs live data, we set :streaming-data? true and it uses web sockets to stream data. Pretty awesome to have the UI slide seamlessly between the server and client like that.

๐Ÿ’ฏ 1
1
dnolen 2025-06-10T18:22:53.824779Z

replicant is also interesting, but yeah I think something that's just Closure aware JS at the bottom but w/ an eye for CLJS integration is missing

borkdude 2025-06-10T18:31:48.416829Z

why would it be necessary to add this to CLJS, people could also just use idiomorph as a lib - what are the benefits? are you thinking of some hiccup thing that integrates well with it?

dnolen 2025-06-10T18:38:32.156859Z

because dependencies on NPM are undesirable for something so basic?

dnolen 2025-06-10T18:38:52.457389Z

diff / morph is at this point no longer a fringe thing

dnolen 2025-06-10T18:43:26.526439Z

also the base thing wouldn't be in ClojureScript, goog.dom.morph or something like that

dnolen 2025-06-10T18:45:05.794729Z

NPM / JS common practice is mostly a trash fire that we have to put up with - I don't think you should have to go there if you don't want to.

cjohansen 2025-06-10T18:46:16.565669Z

The exact reason why I wrote Replicant ๐Ÿ˜…

dnolen 2025-06-10T18:48:11.177679Z

stuff like that is of course nice, but I think we're approaching the moment where just using GCL and CLJS is preferred

dnolen 2025-06-10T18:48:56.153689Z

unfortunately requires a login - but is a 17 minute read

dnolen 2025-06-10T18:49:30.986159Z

every serious CLJS project that requires Node / NPM also takes on this crazy burden of reasoning about the final artifact

borkdude 2025-06-10T18:50:21.411169Z

squint is it's own thing, it's not a thing you add to cljs. not sure if you understood that. I was just showing off basically ๐Ÿ˜‚

dnolen 2025-06-10T18:50:56.910669Z

no no, I get that I meant - I know you can do that ... idiomorph doesn't suffer from the usual problem!

dnolen 2025-06-10T18:53:07.840119Z

rather, I think everyone is familiar w/ getting things from NPM - but dealing w/ that stuff is just more annoyances

dnolen 2025-06-10T18:53:27.593679Z

the ease / peace of mind when something is in GCL is very high (the doc issue aside)

๐Ÿ‘ 1
borkdude 2025-06-10T18:54:30.606759Z

got it

dnolen 2025-06-10T18:54:56.341559Z

and to be clear, I think CLJS integration w/ Node.js / NPM is all fine and good - it's working as well as it would for JS dev

dnolen 2025-06-10T18:56:28.932089Z

but I think having something that's just CLJS-ready would encourage some community exploration of simpler results

borkdude 2025-06-10T18:58:06.547799Z

So 15 years ago you could have added jquery to GCL

dnolen 2025-06-10T18:58:25.527519Z

no need because GCL could already do what jquery did back then

dnolen 2025-06-10T18:59:10.062609Z

that was relatively clear after the initial release

borkdude 2025-06-10T19:00:24.368169Z

yet a lot of people were using jquery in addition to ClojureScript back when it got started?

dnolen 2025-06-10T19:01:05.518519Z

mostly because people didn't know what was in GCL - old habits die hard - not surprising

dnolen 2025-06-10T19:03:26.724239Z

also there's nothing wrong w/ a jQuery like approach even today for lot of things you might want to do. that's more or less how I used CLJS for my blog

dnolen 2025-06-10T19:04:19.773749Z

and I would still use it that way if/when I revive the blog

dnolen 2025-06-10T19:06:22.210709Z

and I don't want NPM deps on my blog thank you very much ๐Ÿ™‚

dnolen 2025-06-10T03:58:29.314679Z

the CLJS printing machinery is significantly cleaner now wrt. DCE. much easier to reason about

โค๏ธ 1
๐ŸŽ‰ 8
dnolen 2025-06-10T03:59:10.564939Z

advanced compiling a trivial source file w/ just a vector is now 32K / 9K gzipped

dnolen 2025-06-10T03:59:24.646989Z

a keyword by itself is 6K (not even gzipped)

dnolen 2025-06-10T04:00:25.628889Z

persistent hash maps pull in significantly more stuff, but even that's smaller 88K / 20K

dnolen 2025-06-10T04:05:16.804099Z

I don't think it will help most programs, but now the results are closer to matching expectations of what Closure can do. and definitely makes it easier to experiment w/ whether "light weight" data structure replacement could provide optional savings.

๐ŸŽ‰ 3
dnolen 2025-06-10T04:09:00.671849Z

having unused persistent data structures at the top level doesn't seem to cause any problems - Closure does eliminate them

dnolen 2025-06-10T04:19:50.032269Z

I would summarize the long-standing issue as not so much printing itself as much as not using JS primitives in the printing implementation

dnolen 2025-06-10T04:20:32.988759Z

There are also a lot cycles between definitions, the one between IndexedSeq and str was particularly bad