Oof that XR bug was a rough one to run into. If you're a small startup trying to move fast with CLJS, these kinds of impedance mismatches between GCC/CLJS/browser versions can be both hard to track down and a time killer to fix.
I really like CLJS, when it works it really feels like you have superpowers - immutable data structures and higher order functions being idiomatic in Clojure makes Reagent more ergonomic than React in vanilla JS.
Additionally the Clojure philosophy of embracing the host makes interop feel quite ergonomic when you do need to duck down into JS.
That said, I wouldn't say that the CLJS->JS compilation is watertight (especially with advanced compilation turned on) and in any non-trivial project you will run into issues as outlined in this blog post. Once you are familiar with the stack most the problems fall into a set of predictable buckets (like the ones mentioned in this article) but debugging them for the first time can be gnarly.
CLJS is not a tool you can use blindly without knowing how it works IMO. But maybe that is true of the modern JS stack itself as there is a lot of churn in JS too.
That said for server-side CLJS we had success turning off advance Closure compilation as package size isn't as much of an issue
> we had success turning off advance Closure compilation as package size isn't as much of an issue
I always thought that package size was just one of the benefits of advanced compilation. It also does other nifty things, like automatically unrolling loops, inlining functions, etc. Those have actual benefits on runtime performance don’t they?
It depends. GCC (the Google Closure Compiler) indeed does some transformations that will improve run-time performance, but it is not its forte, and definitely not its primary goal.
In the benchmarks of Scala.js [1], another compiler that uses GCC behind the scenes, we have shown that:
* the GCC optimizer alone often introduces performance improvements (not always, and sometimes it worsens performance)
* our optimizer does better than GCC on its own
* the combination of both does not improve over using only our own optimizer
Scala.js uses GCC essentially for its code size improvements, not for its impact on run-time performance.
I agree with you.
The project I am currently maintaining, has a complex and monstrously sized front-end production build even with code splitting and advanced compilation activated.
We should embrace server-side rendering more and keep the front-end code simpler and more lightweight.
Have you tried shadowcljs? Its default (:shadow) option is to use advanced optimizations only on your code; it will not run advanced optimizations in libraries but will include them minified. For me, this has struck a good balance and delivers consistently small and dependable bundles.
I really like CLJS, when it works it really feels like you have superpowers - immutable data structures and higher order functions being idiomatic in Clojure makes Reagent more ergonomic than React in vanilla JS.
Additionally the Clojure philosophy of embracing the host makes interop feel quite ergonomic when you do need to duck down into JS.
That said, I wouldn't say that the CLJS->JS compilation is watertight (especially with advanced compilation turned on) and in any non-trivial project you will run into issues as outlined in this blog post. Once you are familiar with the stack most the problems fall into a set of predictable buckets (like the ones mentioned in this article) but debugging them for the first time can be gnarly.
CLJS is not a tool you can use blindly without knowing how it works IMO. But maybe that is true of the modern JS stack itself as there is a lot of churn in JS too.
That said for server-side CLJS we had success turning off advance Closure compilation as package size isn't as much of an issue