Wow, after reading this, I'd be surprised if anyone could come away with the conclusion "Yeah, that's better than JSX."<p>I think the general distaste for JMX is that it "feels" backwards initially: it mixes in HTML snippets within code, while many people are used to template files, which are mainly markup with small bits of "presentational" code injected.<p>But once you realize and really understand that JSX is just shorthand for javascript calls (and the article does a good job of explaining this), you hopefully eventually reach an "Aha!" moment of thinking of JSX in terms of underlying component creation. That's what happened to me, anyway,.
Why JSXBelPack when you can<p><pre><code> import { html, render } from 'https://unpkg.com/lit-html';
const benefitTpl = ({name, desc}) => html`
<dt>${name}</dt>
<dd>${desc}</dd>
`;
render(html`
<lit-rocks>
<dl>${benefits.map(benefitTpl)}</dl>
</lit-rocks>`, document.body)
</code></pre>
And updates are fast without any VDOM overhead.
I used to be really sceptical about JSX, 1 extra transp. step, anorthodox use of xml in JS, etc.<p>Having been using it for the past 3-4 years I think its an above agerage elegant solution when it comes to templating solutions.
Pug is a worthy mention.
<a href="https://github.com/pugjs/babel-plugin-transform-react-pug/blob/master/README.md" rel="nofollow">https://github.com/pugjs/babel-plugin-transform-react-pug/bl...</a> wasn't mentioned
What really bugs me about JSX is the complexity it introduces to the build pipeline - which might be fine for senior developers, but I regularly see junior developers struggle with configuration and errors.
The fact that front end has to deal with 3 different languages (JS + HTML + CSS) is a problem nobody has completely solved.<p>These days the solution usually falls into 3 camps:<p>1) Write everything in JS like React.createElement or Mithril. No build setup but a pain to use.<p>2) JSX. Requires a build setup which might become complex as the project grows.<p>3) Templates. Probably the less elegant of all 3 but the most pragmatic and easy to use.<p>Someone attempted to solve this and created a new language called Imba. It's like a mutant Ruby with HTML that compiles to JS.<p><a href="http://imba.io/" rel="nofollow">http://imba.io/</a><p>It has a lot of productivity benefits compared to previous attempts at solving the same problem, but goddammit it's ugly.
We use virtual jade at work. It works with most virtual doms that use some form of h(name, attrs, children) calls.<p>We have webpack hot reloading so we can work on UI without any page refreshes.<p>It’s been very productive. I love the brevity of jade/pug. Jsx feels like a lot of boilerplate braces and ending tags.<p><a href="https://github.com/tdumitrescu/virtual-jade" rel="nofollow">https://github.com/tdumitrescu/virtual-jade</a>
I would advice against using JSX alternatives. I come from a Clojure background and I like the ijk solution to just use an array to represent the virtual dom.<p>But still I would recommend using JSX because it the "standard". Every documentation and problem solution you find on the internet is written with JSX. Using a JSX alternative will make debugging much harder for you.
HTM actually looks pretty intriguing to me.<p>One thing I like about JSX is that it looks and feels like HTML.<p>For me, that has two huge benefits:<p>1. It narrows the dissonance between the code I'm writing and the actual structure that will be rendering into the DOM. I find it much easier to write and debug when I don't have translate between some JS factory function and the actual DOM implementation.<p>2. It's almost pure HTML. Sure I'll have to change class to className and update some other tags. Generally, though, if something works in HTML, it's little fuss to do in JSX. With tools like JSX, I can write in a single templating language across all of my software.
i'm surprised hiccup was never mentioned. ofc it's not for pure JS but there's this thing - <a href="https://github.com/lantiga/react.hiccup" rel="nofollow">https://github.com/lantiga/react.hiccup</a> though i never tried and don't know how well it works. still interesting.
There's also kotlin-react which let's you write React in Kotlin in a Kotlin DSL which looks exactly like your first imagination probably suggests: <a href="https://github.com/JetBrains/kotlin-wrappers/tree/master/kotlin-react" rel="nofollow">https://github.com/JetBrains/kotlin-wrappers/tree/master/kot...</a><p>It's also a pretty impressive demonstration of the typesafe flexibility of Kotlin's DSL support, but that's another conversation.
A point to the discussion of whether JSX is preferable or not to a programmer, most React projects with JSX I've worked on has had the awesome bonus of a designer who knows markup/css to be able to add layouts to our web and React Native projects. Just wanted to throw that out there as a plus to JSX. I don't think the designer could follow hyperscript very well.
There's also HDOM, part of the larger Umbrella collection of libraries: <a href="https://github.com/thi-ng/umbrella/tree/master/packages/hdom" rel="nofollow">https://github.com/thi-ng/umbrella/tree/master/packages/hdom</a><p>Purported benefits from the readme:<p>- Use the full expressiveness of ES6 / TypeScript to define user interfaces<p>- No enforced opinion about state handling, very flexible<p>- Clean, functional component composition & reuse, optionally w/ lazy evaluation<p>- No source pre-processing, transpiling or string interpolation<p>- Less verbose than HTML / JSX, resulting in smaller file sizes<p>- Supports arbitrary elements (incl. SVG), attributes and events in uniform, S-expression based syntax<p>- Supports branch-local custom update behaviors & arbitrary (e.g. non-DOM) target data structures to which tree diffs are applied to<p>- Component life cycle methods & behavior control attributes<p>- Suitable for server-side rendering and then "hydrating" listeners and components with life cycle methods on the client side<p>- Can use JSON for static components (or component templates)<p>- Optional dynamic user context injection (an arbitrary object/value passed to all component functions embedded in the tree)<p>- Default implementation supports CSS conversion from JS objects for style attribs (also see: @thi.ng/hiccup-css)<p>- Auto-expansion of embedded values / types which implement the IToHiccup or IDeref interfaces (e.g. atoms, cursors, derived views, streams etc.)<p>- Fast (see benchmark examples)<p>- Only ~6.2KB gzipped
Awesome article. I appreciate the lack of bias. Thanks for writing this, OP. It's good to keep an eye on the horizon for potential alternatives to tech we use day in day out, but it looks like we're still on solid ground with JSX so no need to switch :)
There is also a babel-transform for pug[1]. It works quite well as JSX replacement. Not having any endig tags can be quite beneficial when reformatting stuff.<p>Paired with Tachyons (best atomic CSS lib) you get superpowers and can write code like<p><pre><code> const someComponent = ()
=> pug`
ul.p2.f3 Some list
li.red Some text
li.pink Some more`
</code></pre>
[1] <a href="https://github.com/pugjs/babel-plugin-transform-react-pug" rel="nofollow">https://github.com/pugjs/babel-plugin-transform-react-pug</a>
I think a lot of readablity issues with jsx are caused by the amount of logic react devs will put in their markup. It's painfully reminiscent of old-school PHP templating
My problem with JSX is that if you introduce a DSL, why would you limit it to basic function calls/expressions?<p>I created a small language to demonstrate what I mean <a href="https://github.com/batiste/blop-language" rel="nofollow">https://github.com/batiste/blop-language</a>
I was a bit apprehensive about JSX before quickly getting used to it. Now I love it.<p>The only decision I dislike is renaming class to className. Why not klass, cls, cs... anything shorter.<p>ClassName is simple to understand but adds a lot of clutter to component files.
If you read this article and thought Hyperscript might be something you wanted to try, please check out Mithril[0].<p>It's an excellent project, pretty decently fast (checkout the js-framework-benchmark[1] code, or more specifically the results of round 8[2]) -- but is currently suffering from a lack of recognition. It's the kind of project that absolutely doesn't care about that kind of metric (as in, the team seems to be more focused on slow, steady improvement of the library rather than chasing stars on github), but I figured I should say something.<p>Shameless plug: I recently really wanted to contribute something (and kick the tires more) so I wrote an article that goes through replicating a simple mail design I saw[3] -- it might be a decent overview of what mithril is like to write (though I'm certainly not a mithril expert).<p>This brings me back to the point at hand -- as others have noted, in my opinion one of the best things about hyperscript is the straight-forwardness with which you construct the render function. I'm not convinced it's necessary to segregate stateless/stateful components -- and mithril is simpler in that it doesn't introduce this dichotomy -- in the end there's the render function, and that's it. If you want to use state, go ahead -- if you don't, then don't. It's the simplicity I've wanted from component frameworks (and mostly get with Vue) without any of the posturing/looming complexity.<p>Also there's the fact that you could write a completely vanilla es5 application with hyperscript (arguments whether you should or not aside) -- JSX is/was revolutionary, but is basically required in practice, which often makes people jump into bed with webpack without thinking, and makes frontend development harder than it has to be.<p>[EDIT] - Another point for mithril is that it's <i>self contained</i> -- routing and ajax calls some with the framework. When people these days talk about "react" or "vue" what they're really talking about is react/vue + react-router/vue-router + flux/vuex and some other odds and ends. Mithril is by far the simplest and most feature-complete of these frameworks despite being smaller (both conceptually and on-the-wire).<p>One of my only current gripes with Mithril is the lack of controllable subtree rendering (it isn't as much of a problem in practice, but more me wanting to optimize early).<p>[0]: <a href="https://mithril.js.org" rel="nofollow">https://mithril.js.org</a><p>[1]: <a href="https://github.com/krausest/js-framework-benchmark" rel="nofollow">https://github.com/krausest/js-framework-benchmark</a><p>[2]: <a href="https://www.stefankrause.net/wp/?p=504" rel="nofollow">https://www.stefankrause.net/wp/?p=504</a><p>[3]: <a href="https://vadosware.io/post/mithril-systemjs-and-rollup-getting-started-guide/" rel="nofollow">https://vadosware.io/post/mithril-systemjs-and-rollup-gettin...</a>