Before we begin, for context, here is:
If your onClick handler references business-logic functions directly, something is wrong.
Are you still doing that? Stop it. Unless you enjoy manual memory management too. (In which case good luck to you, my fine retronaught.)
Our brains are happiest with a single line of control flow. Yes you can get comfortable with callback-passing, but it never sits as easily as not having to. And like DOM manipulation, you don't have to anymore. It's a job for the language, not for you. Save your brain.
I've heard people complain about the size of the JS files it produces. Apparently in the early days it was particularly bad, but to me, now, it seems perfectly acceptable. Once a production webapp will minify & gzip to less than the size of an animated cat gif, it's time to stop yapping about file sizes.
There were three downsides with GHCJS for me. The first is, how should you structure a full client-side app? I did some work on this with Ben Ford, and then he took it much further, but it's still very much an area of research. I couldn't say to anyone, "This is the way to build it; you'll need these pieces."
The second problem is that GHCi isn't supported yet. Without that, I found incremental build times to be just a bit too long, even for a small app.
And the third problem, and for me the nail in the coffin, is it's a real pain to install. If you thought cabal hell was hell, I can tell you there's another layer of problems lying in wait. Honestly, I couldn't even say to anyone, "You should try GHCJS." Getting started is asking too much.
All these problems will be addressed, and quickly I expect. Simply because of the quality of compiler, GHCJS is the one to watch. But I've put it aside for now.
If Haste needs serious expertise to pass
[1, 2, 3], then it's not for me.
PureScript moves us away from GHC and into languages that are styled-after Haskell. PureScript seems to be winning a popular vote (in this ultra-niche), and I can see why. The language has the headline features from Haskell, interop is good, it all works, and the documentation is excellent.
The compiler errors are...disappointing. Haskell development leans heavily on fast, high-quality feedback from the type system. If you squint, the GHC compiler is almost a REPL. From what I gather, GHC has taken a vast amount of engineering effort to get to where it is, so you can't blame PureScript for lagging behind. But lag it does, and when PureScript spits out a type error, I feel very much alone.
And finally, the "how do we structure/how do we render?" question felt unanswered. There is a virtual DOM library, but it was scrappy. I didn't have an Om-quality experience using it. I'm sure it will get better, but like GHCJS it feels like an untrodden path.
Bonus Tip: If you're playing with PureScript, Take a look at Bodil Stokke's Pulp for your building needs. That worked well for me.
Elm is nice. Very nice. The language is good. Control flow is sane. The documentation is expansive (though more scattered about than PureScript). Incremental compilation times are pleasing. The compiler feedback is good. (No GHC, but better than PureScript.) Interop is so easy it makes you wonder why interop is hard.
The tooling's excellent, even before you get into the fancy stuff like the time-travelling debugger. You can just write some code, compile it in seconds, get a single page you can upload straight to S3, and your website's running. And the path from that to a proper minified, production app is smooth enough.
I've heard people say Elm is great for game-like things, but little attention has been given to regular HTML apps. That's not true. The elm-html library is, give or take, a perfect substitute for Om/React.
And the FRP approach may prove a bit of a learning curve for some, but I found it very natural. There's a certain way that I've been structuring my ClojureScript apps, and Elm feels like it's taking the same route, but has baked it into the language. I heartily approve.
On the downside, I do really wish it had typeclasses. And not even for
shiny things like putting my monoids in the category of
endofunctors. Just for simple stuff. Having to qualify
Set.map gets old very quickly. And Json decoding
would be much simpler if it supported return-type polymorphism.
As you can probably guess, for now I've settled on Elm. I'm building an MVP for a startup of my own at the moment, and the front end is Elm. I'll let you know how it goes.
Oh, and I'll be keeping my eye on GHCJS...