I plan on using Clojure for backend - Datomic + Ions makes learning curve / investment in CLJ clearly worth it.
But I’m unsure of whether to use CLJS for front-end. I’ve explored ecosystem, and see how it could have definitely been a great choice a couple years ago – with Reagent/Re-frame or Fulcro. Prior to React’s hooks / context API, I’m sure this solved a lot of headaches. I was actually surprised to see how complete the dev story was. But as of now, these tools haven’t yet caught up to modern React and its new concurrent mode features. And while there’s new libraries like @lilactown’s hx or helix, they’re still relatively new.
Also, while react hooks might make easier to use React in cljs, they also make it less painful to use in js. With eslint (linting), typescript (static typing), jest (testing) and apollo/relay (data-fetching) the development experience is pretty good.
Which is why I wanted to discuss: is Clojurescript still worth it for a JS React dev? It’s a genuine question, and I’d love to be convinced that it is.
To be clear, I’m coming from a place where I’m confident with JS front-end development. But because I’m learning Clojure for backend, I’d also like to use it in front-end if trade-offs are worth it.
My main concern is the extra overhead involved in not embracing the platform, and in wrapping so many JS libraries for usage.
@thheller’s shadow-cljs provides better javascript interoperation, and he’s even added react native and expo support! But he’s only a single maintainer, so while I do believe he’s going a great job, I’m hesitant to build the backbone of my app on it. Plus, if there’s unsupported use-cases, such as using cljs with next.js, I likely won’t be able to contribute that work myself since I’m just getting started.
Here are three factors I find clearly superior in cljs development:
- repl experience
- immutability
- clojure’s lisp syntax for composing components (rather than clunky jsx and js tertiary experiences)
I won’t be able to replicate the repl in JS land, unfortunately. But immutability can be done with Immer.js - though obviously the functional utilities wouldn’t be as nice.
Factors I find superior in js development:
- embracing the platform
- static typing with typescript (useful since there’s a lot of glue code in front-end, specially when passing component props around)
- linting of graphql queries with eslint (along with checking for errors, makes it easy to locate API warnings/deprecations)
- more completely testing story n logging via jest
- easily use more complex libraries like Relay, Prosemirror, and Storybook
In terms of performance, I’m unsure of impact cljs has nor could I find much discussion of it online. There’s of course the extra cljs code overhead. But that has to be balanced with any libraries I’d use to makeup for what clojure gives me in js land (so maybe immer and lodash). Though I’m sure wrapping so many js libraries also adds to bundle size, too.
Another factor to consider is error handling, though I haven’t gone deep enough in a project to comment, it is yet another platform layer to account for when debugging, so figured I’d mention it.
Anyway, I’d love to hear about experiences using or not using cljs in newer projects, and if you’d like to correct anything I mentioned above, or expand on it, please feel free to do so. Obviously we’re biased here but still would be great to hear what clojure devs have to say, thanks!