I am learning to write simple web applications. I started with Clojure, Ring and Hiccup. I am progressing, so I believe I am not on a wrong path.
Now I am at the point where I want to integrate some JavaScript code into the html pages: Simple things like mouse events, changeing colors and requesting more contents. The JavaScript code in Hiccup are strings. And this is what I am not very happy about.
I always thought, that the goal of ClojureScript is to use the same language on the server and on the backend. But after reading tutorials and trying to become a friend of ClojureScript I have the impression, that ClojureScript cannot be mixed with Clojure.
All tutorials I can find generate the html pages on the client and use the server only for delivering pure data. I believe, that would work well and the frameworks would make it as easy as possible. But I donât plan to develop such big web plattforms, where the huge effort for learning all these technologies pays off. I only want to create simple web applications, that come ready as html files out of the server with a bit of JavaScript integrated.
Do I misunderstand ClojureScript? Shouldnât ClojureScript code be part of the Clojure Hiccup machinery on the server and converted to JavaScript during compilation?
The typical arrangement is to use the clojurescript compiler (often w/ a tool such as shadow-cljs, or figwheel, or lein cljsbuild) to compile your clojurescript to javascript ahead of time, and then load the clojurescript-compiled-as-javascript files into your pages.
If you have code that you want to compile for both the jvm, and for js, it is possible to use .cljc files.
None of this necessitates any heavy frameworks. You can compile a small amount of clojurescript into a small amount of javascript, and load it like you would any other javascript.
I have the impression, that ClojureScript cannot be mixed with Clojure.
Thatâs true, although thereâs a big overlap between what each supports. If a file can be run as both ClojureScript and Clojure, itâs usually given a filename which ends in .cljc.
But I donât plan to develop such big web plattforms, where the huge effort for learning all these technologies pays off. I only want to create simple web applications, that come ready as html files out of the server with a bit of JavaScript integrated.
Youâre not the only one to want that. Cherry and Squint, both by the redoubtably productive @borkdude, are very promising solutions for your use-case. They enable you to turn ClojureScript-like code into JavaScript without relying on the relatively heavy Google Closure library.
I donât plan to develop such big web plattforms, where the huge effort for learning all these technologies pays off
Pretty much all of the tools that are needed to compile CLJS into JS have some sensible defaults that make working with small applications as easy as creating a config file with barely any data in it (and even this step is optional) and calling a single CLI command.
I only want to create simple web applications, that come ready as html files out of the server with a bit of JavaScript integrated.
Thing is, compiling CLJS into JS is not a trivial task, conceptually. Itâs also slow, so if you want to embed CLJS code inside Hiccup forms, youâd have to cache the data, which already makes it all much less trivial than calling a single command to compile it all in advance.
And, while CLJS and CLJ are very similar, they have enough differences where some form can be valid in CLJS but invalid in CLJ (e.g. the #queue reader immediately comes to mind).
If you only want to create a simple web application, then I would recommend to consider using HTMX. Only reach for ClojureScript if you need to design a very interactive UI (like an image editor for example).
I recently wrote a blog post series on different strategies for using CLJS.
The idea of embedding CLJS directly into hiccup may seem appealing, but will not scale well. It didnât work with JS and it wouldnât be any better CLJS. Instead you want to make functions available in the client, that you can re-use in different places, with strategies such as âgraftingâ to âcallâ them from the server generated hiccup.
There is absolutely nothing heavy about the Closure Library, unless you use like 90% of it. CLJS itself uses less than 1% so it is never a worry that this is too heavy. What is heavy is cljs.core itself, since it has to provide all the persistent datastructures and core library. It optimizes decently well, but there is always a baseline cost associated with it.
I believe it always pays off to understand what you are working with, but if you wish to skip most of it you can maybe get by with learning the often discussed HTMX library instead. Iâd strongly encourage to learn CLJS and a bit of DOM instead though, even if the learning curve is substantially steeper at first. Itâll be worth it in the end, and if you already know CLJ the CLJS part isnât that hard.
I thought Iâd do some small experiments as itâs been a while since I used ClojureScript. Hereâs what I found: a ClojureScript âhello worldâ program currently produces about 5MiB of JavaScript; with dead-code elimination that goes down to 96KiB right now. Thatâs not a disaster, but itâs considerably more than what youâll get when using something like Squint: less than 1KiB after passing through esbuild. (Cherry actually produces three times as much code as ordinary ClojureScript though, so Iâm not sure why the esbuild tree-shaking doesnât seem to catch that).
Indeed; theyâre not directly comparable. However, it sounds to me like @habruening wanted something like a very thin layer over JavaScript to provide a functional programming environment with s-expressions. Thatâs certainly what Iâm often looking for, so of course I might be over-projecting my own interests here.
I feel that that the relationship between ClojureScript and JavaScript is quite like the relationship between Pascal and x86 machine code: as a ClojureScript programmer, you hardly ever need to think about what JavaScript is being generated unless youâre creating a wrapper for an existing JavaScript library. Likewise, Pascal gives you this cozy environment where the CPU architecture is almost entirely abstracted away.
The relationship between Squint and JavaScript feels more like embedded C and machine code to me. Thereâs still loads of abstraction, but when youâre pushing bytes into buffers by their addresses and multiplying pointer widths together, itâs hard to forget that what platform youâre writing for. With a good disassembler and -Og in your CFLAGS, you can directly see what machine code a given portion of C produces.
Thanks for letting me know; that looks really useful
Thank you to all for the detailed answers! This was very helpful. I was searching a very light solution. The solutions like squint are still too heavy. My html files have only a very few lines of JavaScript. Mostly one-liners that set a variable to something or call something.
I decided now to write my own Clojure syntax for JavaScript, which is converted to a string by functions and a macro. In case someone is interested, I paste here my draft.
I also did some research and made my experiences, so I share with the readers what I think two months later.
If you have a static web site or a web site that does not contain many interactive elements, it definitively makes sense to go only server based and use such a simple JavaScript library. In my opinion.
If you donât have such a simple situation, you must make a decision first. The question whether you do things client based with ClojureScript or with Clojuje also depends on where you want to have the state. If you work client based, that means, your data model is in the client. The client application runs at certain level independent from the server. It may be faster and more robust against connection problems. This is normally what you want, when you develop a âvery interactive UIâ as @maxweber wrote. If you develop a text editor you donât want each character you type to be sent over the wire. The other option is that you have your data model on the server and you regard the client only as the representation. In the first case the connection between server/client is based on something like JSON and you may work with ClojureScript on the client. In the later case the connection is based on HTML, you will not have so much code on the client, so it is not so much of concern how you generate the few JS code for the client. Both options are make sense. But the question where and how you want to have your data model comes first. And this implies the answer to the question if you use ClojureScript or not.
It is very tempting to start server based with pure Clojure, because everything is so easy. You can do more things that you would have expected. A few answers point to HTMX. But I guuess many people who start like this, regret this decision later.
What I also found out that things like react, where a complete machinery runs on the client have many motivations. I donât illustrate it here. But I think two points are worth mentioning here.
They are good for companies like Facebook or X, because with pure client based rendering they save much computation time and much cost for their server infrastructure. However, if you run a very small web site, this is not relevant.
Most JS frameworks push the developers towards an approach with unidirectional data flow and immutable updates. In Clojure this is not so unusual. So we donât need a framework that manipulates us in this way.
That been said, makes me a bit sceptical when taking over things that are well established in the JS world. So I will continue with my server based approach, because I donât plan web sites with much complexity and interactivity.
For most of you all this may be nothing new. But for me it was new. This was why I was asking this question and the answers helped me a lot to understand things better.