SGML (the markup meta-language once used for describing HTML) has that, but as we're talking the verdict is still out whether that's actually easier [1] ;) But anyway, SGML gives you HTML-aware, context-dependent, injection-free templating (even with hard support for sanitizing user content) in a content authoring workflow independent from a hosting programming language so is in a different ball park.
You can't build an IDE that definitely just "understands Rust macros" since procedural macros in particular are in effect modifying your compiler. Maud is a proc macro.
Mara's whichever_compiles! macro for example: https://github.com/m-ou-se/whichever-compiles -- that macro is forking your compiler to try out all the branches and throwing away branches which caused a compile error.
Clearly your IDE should throw its hands up and say, I don't understand what this does, I give up.
In general doing something useful with Rust macros is a more tractable problem for an IDE than say the C pre-processor, because Rust's macros have a stronger syntax, but the proc macro is potentially much too powerful / dangerous to try to evaluate.
It ultimately depends on how they're written. println! is a macro, and doesn't "break the tooling". on the other end of the spectrum, using a crate like demonstrate (unit testing) produces hard to understand errors and slows down the IDE.
I don't remember experiencing Rust Analyzer crashes for a long time, though (I do remember some in the past).
println! is only a declarative macro, whereas Maud is a proc macro.
The declarative macros aren't too head-twisting for tools, they just expand as declared, this can sometimes have a few surprising effects but generally it is very manageable. Procedural macros have essentially unlimited power and thus are sometimes entirely impossible to analyse.
Maud is wonderful for small things like a stats page or dashboard.
But once you start getting to a few pages it's so much less cognitive overhead to separate concerns out into proper html files/templating.
It seems quite daunting to have a large project where all your html is inside rust files and a lot harder to find people who can work on it proficiently.
I think it isn't the consensus anymore because there isn't actually a "correct" solution. It's too subject to personal preference. For example, I prefer having HTML + CSS + JS all in the same file because then I know everything relevant to the component or page I'm working on is right there. I do concede that it can get extremely unwieldy if you don't separate out components though.
One of the huge advantages of Maud is that it keeps code and markup close together, so you can do things like having rust control structures determine what markup is used later on (for snippets or widgets, for example).
Plus, Maud has a definitive speed advantage from what I've noticed.
Sadly, there isn't any great alternative for making performant HTML templates in Rust from what I've seen, a lot of the other HTML templating libs aren't that great comparatively.
> Sadly, there isn't any great alternative for making performant HTML templates in Rust from what I've seen, a lot of the other HTML templating libs aren't that great comparatively.
Which others have you tried, and why do you think they're not great?
I've tried handlebars and liquid. They're okayish, but both slow and don't have any compiletime help or typing when I tried them.
Horroshow, ructe, typed-html and yarte were okay but inheritance was underdocumented (or generally not as well documented), which is a big no for me. And a few only give minor-quality help at compile time.
Maud on the other hand has decent compiletime help and doesn't require a lot of documentation as normal rust code is doing the heavy lifting.
I haven't found askama yet, or rather, discovered it through HN here, I don't check the arewewebyet.org site too often and it's my main source of frameworks to find.
My main worry on things is that I'd rather like being able to express the inheritance in the type system through generics. Ie, having a top level "Page<T>" struct in which I can start putting the various subparts needed to render a page. It seems askama is doing it the other way round with a "parent" member needed in the child page.
> One of the huge advantages of Maud is that it keeps code and markup close together
I'd say it's actually a disadvantage. Front end engineers will work with HTML with embedded logic (as little as possible - values, iterators, conditionals). Generating HTML from Rust code is nice for simple things, but won't work with complicated HTML templates when those are required and will be harder to integrate with front-end applications. It's possible to compile a template with embedded logic (Java Server Pages did that in the late 1990's) to performant and type safe code. An approach like that would be great for Rust (someone must have done it by now)
My projects have no front-end engineer, however. The frontend is written in Rust as well and also uses Maud for HTML templating.
And I dispute it not working with complicated HTML templates, that's handling it fine and integrates very well since I share code between frontend and backend anyway.
I get that, but Maud is not the first of its kind and the absence of similar engines in web development is a telltale sign it's not the optimal approach.
Well, as mentioned, I've yet to find something that can replace Maud without sacrificing it's advantages (in-code inheritance, code-sharing and compile-time type-safety).
So even if it's not the "optimal approach" as you title it, it's the ergonomic approach for me because it doesn't get in my way.
Askama should be comparable in speed and type safety? It probably doesn't integrate any better inline with source though (I've only used it with standalone template files).
Askama looks interesting, though the inheritance is a bit underdocumented.
Ideally, I'd imagine just making a "Global<T>" struct, where I insert the current page context like so "Global<LoginPage>" to get the final template. Though by the looks, it sounds more like LoginPage will simply have to have all the global context available via some attribute like "LoginPage.global".
I do, in theory, understand separation of concerns.
But as someone who works on a sprawling set of template files with loads of sprinkled conditionals in a template language... the idea of using a "real language" for the templating, and in particular having type checking and proper abstraction tools (you can just write functions! No weird template tag tricks) is so much nicer to me.
HTML templates have always felt super brittle to me, basically at the level of C preprocessor programming. Even just with React/TS you can get away with so much with way more confidence given the typed backing.
Though I think that you _could_ get away with some nice tricks in Rust thanks to macros, where you ingest the template files and generate render functions with all the properties... or something like that.
What? Outputting HTML is basic enough that most languages don't need to use macros for this.
I don't understand why'd you want to use macros with all its problems to generate HTML, when even a simple data structure like "vectors in vectors" would do just fine to generate HTML (ala Reagent in Clojure-land).
People like to hate everything related to JS these days. But when I see libs like these I'm just very grateful for the person(s) who invented JSX [1]. And evenly for MSFT implementing it into TS as a first-class citizen. It's just so much more readable.
Scala is the only other language I know of which has some kind of XML/HTML syntax support (scala.xml). (But it looks like it got removed. [2])
I find that very interesting, I have the opposite reaction to JSX. Not wanting to use it has been one of the biggest reasons I have moved into using ClojureScript/Hiccup for front-end applications.
I find JSX extremely hard to read and work with and reason about.
After you get a taste of the free world of hiccup/reagent where it's just vectors and maps to create HTML, its really hard to imagine going back to anything else. Being able to use the same programming language in your "HTML template" (which are just core data structures in a specific shape) as for the rest of your programming is just icing on the top.
Small example for people to understand the difference:
I think the big differences don’t come out visually.
In JSX you might be struggling with expressing certain things, because JS has a statement expression syntax. So you have to circumvent that. In Clojure everything is an expression already.
In JSX you can manipulate components with HoCs. In Clojure it’s just data, no special ceremony needed.
On the client, if you’re using React, you might use hooks to keep travk of state, which are a special construct that don’t exist in JS. In Clojure, if you use something like reagent, you just use atoms, they have a special purpose implementation, but they look and feel like regular old atoms.
However I have to say, JSX and React are very productive even with those limitations, simply because the tooling around it is so good.
Hopefully the limitations around expressions in JS will go away at some point and JS will become properly expression orientated. There are already proposals for this, although they currently seem to be stalled.
I don't think JSX is very readable. If you squint it may look like HTML, but when you try to actually read it, it's all off. Different attributes, bizarre templating, blurred line between rendering and code. The latter in practice is always a complex mix of view/state/ callbacks with react.
You're confusing JSX and the React target for JSX; only the latter has the problems you mention.
This is a very common confusion because most people approach JSX via React, and as such never really grasp that JSX is a separate, independent thing. If you're interested in learning it standalone, I'd highly recommend working with either the Typescript `jsxFactory` compiler option, or the `@babel/plugin-transform-react-jsx`
Isn't JSX essentially syntax sugar for function calls (to a specific "create element" function), and therefore bound to code/rendering mix regardless of React? I see JSX syntax as fancy JS expressions. It seems like everything the parent said could apply to any use of JSX, except for the attribute naming issue.
The "opposite" approach being using a template language like the one in Svelte or Angular… or like PHP (or Velocity, or Jinja) (for me JSX is not a template syntax at all).
I think template languages are also prone to rendering / logic mix, I don't know what is an elegant solution to this problem apart from getting used to this reality. Maybe something like QML, using data models, instead of having a for loop to render lists for instance.
> Isn't JSX essentially syntax sugar for function calls
Yes. Which makes any issues the gp mentioned entirely up to the implementation of that function call.
> seems like everything the parent said could apply to any use of JSX, except for the attribute naming issue
If by "could apply", you mean anyone could write a function that has those issues, then yes I guess. My point was that if you want to avoid those, they're in no way inherent to JSX. Is that what you meant?
I mean, I guess "blurred line between rendering and code" is less about the function implementation, and more about project / file organisation choices (including conventions of a frontend view framework community), but it's still certainly not inherent.
> I think template languages are also prone to rendering / logic mix
True. I think you do need a lot of discipline if you want to keep a clear and consistent separation, and it's also not always worthwhile (there's a codebase-approachability trade-off with abstraction & locality of context).
I think I don't agree: I think the possibility of mixing rendering and logic is inherent to JSX. While users of the syntax can probably (deliberately) avoid mixing rendering and logic too much, there's no implementation of JSX that can prevent its users from mixing the logic and the rendering if they want to do so: it will always be possible for a user to mix the JSX tags with arbitrary Javascript because the full JS language is available in JSX tags and JSX tags can be used in Javascript code.
In contrast with HTML, where there is no way one can mix the logic and the UI because it is syntactically impossible. You have to get the DOM element from a script and to fill it data (well, actually, you can with the script tag and on* attributes, but let's consider HTML without them, only allowing script tags in <head> for instance so our restricted version of HTML remains useful).
I think you need the rendering to be data, not code, to "forbid" this mix (and soon enough, you reinvent some kind of lisp I guess)
I guess I’m not sure what you want though. If you want to render things dynamically, that dynamism has to live somewhere. And wherever that is, it’s possible to abuse. For example, what does “fill in the data” really mean? For a non-trivial app it has to mean the ability to generate fresh markup from your data, and that process can mix concerns.
> there's no implementation of JSX that can prevent its users from mixing the logic and the rendering if they want to do so: it will always be possible for a user to mix the JSX tags with arbitrary Javascript because the full JS language is available in JSX tags and JSX tags can be used in Javascript code.
That's fair. If that's what you're looking for, then JSX is not the answer. I don't think we disagree though - I was merely pointing out separation is possible (even if not strictly enforced).
Personally, I am a fan of the component-driven model (criticised above for "blurring the lines"). As I mentioned, it's a trade-off, and I think any potential "blurriness" is far outweighed by the context and reduced abstraction wins from a code-readability & codebase approachability perspective. Heavily separated templating efforts often leads to codebases with deeply nested hierarchies for views -vs- controller logic that require having 4+ split pane editors open just to understand extremely local snippets of data flow. This is particularly egregious when e.g. trying to audit codebases for injection mitigation.
Hmm, I think a long time ago (around 2005 or 2006) JSX was briefly considered to be party of ES standard. It didn't make it, and shortly after FB introduced React.
Think it may have being easier if JSX is just included in ES as a standard. So yes and no, JSX introduced by FB via react is a just a syntax sugar, however the original JSX is a meant to be a ES standard, with each node as a tree structure.
No, I am not confusing them. My comment is about JSX' awkward attribute (re-)names, only expressions in brackets but full function calls in loops (map). It's horrible.
> only expressions in brackets but full function calls in loops (map)
Not sure what you mean here. Function calls are expressions - they work bare in brackets & also as method args (like the arg passed to the map method on an array prototype, which is called while "loop"-ing that array). This is all Javascript functionality, not really specific to JSX in any way?
I stand corrected about JSX attribute renaming! However I still see it being applied in practice for 99% of JSX use cases.
The problem with "only expressions in brackets" is that then you can write code in the template, but it's massively different to regular code. Worst of both worlds: code in templates and weird subset of code.
If this is undesirable as a feature, then yes, JSX is not an appropriate choice. JSX is the furthest thing from logic-less templating. But that's a deliberate design decision.
> it's massively different to regular code
It's not. It's just regular code - there are no differences.
> weird subset of code
It's not weird. It's any JS expression. All JSX brackets are values, and JS statements don't have return values, so embedding a JS statement within a JSX value would serve no purpose. What would it do?
All statements in JS can be expressed as expressions directly (ternary/array methods) or indirectly (nested within a function expression), so there's no loss of functionality - it's not even really a subset in that sense.
> It's not. It's just regular code - there are no differences.
> All statements in JS can be expressed as expressions directly (ternary/array methods) or indirectly (nested within a function expression), so there's no loss of functionality - it's not even really a subset in that sense.
You're just stating the difference between a statement and an expression. FYI, other languages (e.g. rust) have embraced the "everything is an expression" and it works extremely well, where JSX wouldn't be so awkward (in this aspect) and we could write something like:
Now, if you want to write this in actual JSX, you have to do this:
<div>{(!!list && list.length) // awkward way of writing code
? list.map(e => {
if (e.items?.length) { // normal way of writing code
return <div>Excellent!</div>;
} else {
return <div>Not good.</div>;
}
})
: <div>Nothin to see.</div>
}</div>
Do you see the contradiction of being forced to use only expressions, only in some places? And this happens all the time. The most frequent thing we do in UI is rendering lists, so we use `.map` with "regular" code constantly, mixed with the awkward "expressions only" areas. Sure, the reason is that JavaScript is like that, but that doesn't make JSX any better.
E4X couldn't really be used - it was never available enough (just one major browser) and there was no polyfill or to-JS compiler (those things weren't common at that time).
Had E4X been more widely released, I might have used it, as might many others. In retrospect, though, it's probably good that it didn't catch on, as it introduced a lot of extra syntax and operators, like a.@b, a.@*, a.*, a.b::c, a..b, a.(@b==x) and had semantics that affected large parts of the JS Runtime (how the delete operator works, how calling works, what += means, and so on).
To me JSX is the opposite of what Maud (Kotlinx.html, Elm's HTML lib, Haskell's type-of-html) does. In Maud you write "just code", and "as code". In traditional template engines you have a big string with holes, if-elses and loops. In JSX you write templates as if it is a traditional templating engine, but under the hood it gets translated to JS-code.
Somehow JSX seems to be "worst of both worlds" to me.
Some of these HTML-templates-as-code libs (like Kotlinx.html) are generated from a formal HTML specification. This is really nice, and makes it more type safe (only allow tag nesting that is allowed, and only allow attributes that are allowed; ofcourse with escape hatches).
And as other commenters note, it's designed around React internals, meaning you get rules around capitalisation that wouldn't otherwise exist. And so on.
The difference is that maud does most of the work compile-time, so `html! { div { "foo" } }` compiles into literal "<div>foo</div>" hardcoded in the program, without allocating intermediate HTMLTagBuilder objects.
Oh this looks great! It reminds me of haml, where it is so much easier to see the structure of your file, and you avoid a whole class of dumb typo bugs. And I'm happy to see this doesn't serialize the arguments into json and back (as Tera does). What is the point of that? Every time I start a new project in Rust/React/Elixir I look for a haml-like templating library. For private JS projects I'm stubbornly using a pug-to-jsx babel plugin, but in other languages I'm mostly out of luck. I have several small Rocket projects now where I'm using Tera (handlebars basically). I'll happily switch them to Maud. Thank you for building this!
85 comments
[ 3.6 ms ] story [ 156 ms ] threadhttps://maud.lambda.xyz/control-structures.html
[1]: https://news.ycombinator.com/item?id=31637910
Mara's whichever_compiles! macro for example: https://github.com/m-ou-se/whichever-compiles -- that macro is forking your compiler to try out all the branches and throwing away branches which caused a compile error.
Clearly your IDE should throw its hands up and say, I don't understand what this does, I give up.
In general doing something useful with Rust macros is a more tractable problem for an IDE than say the C pre-processor, because Rust's macros have a stronger syntax, but the proc macro is potentially much too powerful / dangerous to try to evaluate.
https://rust-analyzer.github.io/blog/2021/11/21/ides-and-mac...
I don't remember experiencing Rust Analyzer crashes for a long time, though (I do remember some in the past).
The declarative macros aren't too head-twisting for tools, they just expand as declared, this can sometimes have a few surprising effects but generally it is very manageable. Procedural macros have essentially unlimited power and thus are sometimes entirely impossible to analyse.
I like, use, and write macros, but this isn't fully true. For example, recent Rust versions allow writing identifiers directly in the format string:
However, this breaks rust-analyzer's ability to rename variables [1].[1]: https://github.com/rust-lang/rust-analyzer/issues/11260#
But once you start getting to a few pages it's so much less cognitive overhead to separate concerns out into proper html files/templating.
It seems quite daunting to have a large project where all your html is inside rust files and a lot harder to find people who can work on it proficiently.
Plus, Maud has a definitive speed advantage from what I've noticed.
Sadly, there isn't any great alternative for making performant HTML templates in Rust from what I've seen, a lot of the other HTML templating libs aren't that great comparatively.
Which others have you tried, and why do you think they're not great?
Horroshow, ructe, typed-html and yarte were okay but inheritance was underdocumented (or generally not as well documented), which is a big no for me. And a few only give minor-quality help at compile time.
Maud on the other hand has decent compiletime help and doesn't require a lot of documentation as normal rust code is doing the heavy lifting.
My main worry on things is that I'd rather like being able to express the inheritance in the type system through generics. Ie, having a top level "Page<T>" struct in which I can start putting the various subparts needed to render a page. It seems askama is doing it the other way round with a "parent" member needed in the child page.
I'd say it's actually a disadvantage. Front end engineers will work with HTML with embedded logic (as little as possible - values, iterators, conditionals). Generating HTML from Rust code is nice for simple things, but won't work with complicated HTML templates when those are required and will be harder to integrate with front-end applications. It's possible to compile a template with embedded logic (Java Server Pages did that in the late 1990's) to performant and type safe code. An approach like that would be great for Rust (someone must have done it by now)
And I dispute it not working with complicated HTML templates, that's handling it fine and integrates very well since I share code between frontend and backend anyway.
So even if it's not the "optimal approach" as you title it, it's the ergonomic approach for me because it doesn't get in my way.
https://djc.github.io/askama/creating_templates.html#the-tem...
Regardless, it's good to see some variety and experimentation like Maud in software design
Ideally, I'd imagine just making a "Global<T>" struct, where I insert the current page context like so "Global<LoginPage>" to get the final template. Though by the looks, it sounds more like LoginPage will simply have to have all the global context available via some attribute like "LoginPage.global".
But as someone who works on a sprawling set of template files with loads of sprinkled conditionals in a template language... the idea of using a "real language" for the templating, and in particular having type checking and proper abstraction tools (you can just write functions! No weird template tag tricks) is so much nicer to me.
HTML templates have always felt super brittle to me, basically at the level of C preprocessor programming. Even just with React/TS you can get away with so much with way more confidence given the typed backing.
Though I think that you _could_ get away with some nice tricks in Rust thanks to macros, where you ingest the template files and generate render functions with all the properties... or something like that.
I don't understand why'd you want to use macros with all its problems to generate HTML, when even a simple data structure like "vectors in vectors" would do just fine to generate HTML (ala Reagent in Clojure-land).
Clojure simplicity is just superb in this case.
Scala is the only other language I know of which has some kind of XML/HTML syntax support (scala.xml). (But it looks like it got removed. [2])
[1] https://reactjs.org/docs/introducing-jsx.html
[2] https://github.com/scala/scala-xml
https://docs.hhvm.com/hack/XHP/introduction
https://github.com/phplang/xhp
XHP was launched in 2010 (https://www.facebook.com/notes/10158791323777200/)
The first version of FaxJs (the precursor to React) was launched in 2011, being directly inspired from XHP (https://github.com/jordwalke/FaxJs)
React was made in 2012 by the same person who made FaxJs, taking the best ideas from FaxJs and creating React.
So yeah, JSX actually comes from the idea of XHP :)
The concept was popular at Facebook, so it made its way into HPHP, HHVM, and later ReactJS.
I find JSX extremely hard to read and work with and reason about.
Small example for people to understand the difference:
In JSX you might be struggling with expressing certain things, because JS has a statement expression syntax. So you have to circumvent that. In Clojure everything is an expression already.
In JSX you can manipulate components with HoCs. In Clojure it’s just data, no special ceremony needed.
On the client, if you’re using React, you might use hooks to keep travk of state, which are a special construct that don’t exist in JS. In Clojure, if you use something like reagent, you just use atoms, they have a special purpose implementation, but they look and feel like regular old atoms.
However I have to say, JSX and React are very productive even with those limitations, simply because the tooling around it is so good.
This is a very common confusion because most people approach JSX via React, and as such never really grasp that JSX is a separate, independent thing. If you're interested in learning it standalone, I'd highly recommend working with either the Typescript `jsxFactory` compiler option, or the `@babel/plugin-transform-react-jsx`
The "opposite" approach being using a template language like the one in Svelte or Angular… or like PHP (or Velocity, or Jinja) (for me JSX is not a template syntax at all).
I think template languages are also prone to rendering / logic mix, I don't know what is an elegant solution to this problem apart from getting used to this reality. Maybe something like QML, using data models, instead of having a for loop to render lists for instance.
Yes. Which makes any issues the gp mentioned entirely up to the implementation of that function call.
> seems like everything the parent said could apply to any use of JSX, except for the attribute naming issue
If by "could apply", you mean anyone could write a function that has those issues, then yes I guess. My point was that if you want to avoid those, they're in no way inherent to JSX. Is that what you meant?
I mean, I guess "blurred line between rendering and code" is less about the function implementation, and more about project / file organisation choices (including conventions of a frontend view framework community), but it's still certainly not inherent.
> I think template languages are also prone to rendering / logic mix
True. I think you do need a lot of discipline if you want to keep a clear and consistent separation, and it's also not always worthwhile (there's a codebase-approachability trade-off with abstraction & locality of context).
For arguments' sake though here is a quick-and-horribly-dirty example of JSX syntax separation (not recommended but demonstrative): https://codepen.io/lucideer/pen/jOZvwVz?editors=0010
In contrast with HTML, where there is no way one can mix the logic and the UI because it is syntactically impossible. You have to get the DOM element from a script and to fill it data (well, actually, you can with the script tag and on* attributes, but let's consider HTML without them, only allowing script tags in <head> for instance so our restricted version of HTML remains useful).
I think you need the rendering to be data, not code, to "forbid" this mix (and soon enough, you reinvent some kind of lisp I guess)
That's fair. If that's what you're looking for, then JSX is not the answer. I don't think we disagree though - I was merely pointing out separation is possible (even if not strictly enforced).
Personally, I am a fan of the component-driven model (criticised above for "blurring the lines"). As I mentioned, it's a trade-off, and I think any potential "blurriness" is far outweighed by the context and reduced abstraction wins from a code-readability & codebase approachability perspective. Heavily separated templating efforts often leads to codebases with deeply nested hierarchies for views -vs- controller logic that require having 4+ split pane editors open just to understand extremely local snippets of data flow. This is particularly egregious when e.g. trying to audit codebases for injection mitigation.
Think it may have being easier if JSX is just included in ES as a standard. So yes and no, JSX introduced by FB via react is a just a syntax sugar, however the original JSX is a meant to be a ES standard, with each node as a tree structure.
https://www.ecma-international.org/publications-and-standard...
E4X was supported by Firefox for a while, but I think support was removed.
For instance classes in JS are sugar syntax to define a function that defines fields in this and prototype members of this function.
Arrow functions are sugar syntax to define functions bound to a specific this.
async / await is sugar syntax for promises.
for..of is sugar syntax for iterating over an iterable.
The attribute renaming is a React feature. JSX doesn't rename attributes. See here for example https://codepen.io/lucideer/pen/jOZvwVz?editors=0010
> only expressions in brackets but full function calls in loops (map)
Not sure what you mean here. Function calls are expressions - they work bare in brackets & also as method args (like the arg passed to the map method on an array prototype, which is called while "loop"-ing that array). This is all Javascript functionality, not really specific to JSX in any way?
The problem with "only expressions in brackets" is that then you can write code in the template, but it's massively different to regular code. Worst of both worlds: code in templates and weird subset of code.
If this is undesirable as a feature, then yes, JSX is not an appropriate choice. JSX is the furthest thing from logic-less templating. But that's a deliberate design decision.
> it's massively different to regular code
It's not. It's just regular code - there are no differences.
> weird subset of code
It's not weird. It's any JS expression. All JSX brackets are values, and JS statements don't have return values, so embedding a JS statement within a JSX value would serve no purpose. What would it do?
All statements in JS can be expressed as expressions directly (ternary/array methods) or indirectly (nested within a function expression), so there's no loss of functionality - it's not even really a subset in that sense.
> All statements in JS can be expressed as expressions directly (ternary/array methods) or indirectly (nested within a function expression), so there's no loss of functionality - it's not even really a subset in that sense.
Do you not see the contradiction?
Vanilla javascript assignments can be any expression.
JSX assignments (the brackets) can be any expression.
There's no weirdness nor extra limitations to JSX assignments compared to normal vanilla JS. It works exactly the same.
If you think not being able to assign JS blocks is weird you're going to have to explain to me what this piece of JS code would do:
https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Rel...
Had E4X been more widely released, I might have used it, as might many others. In retrospect, though, it's probably good that it didn't catch on, as it introduced a lot of extra syntax and operators, like a.@b, a.@*, a.*, a.b::c, a..b, a.(@b==x) and had semantics that affected large parts of the JS Runtime (how the delete operator works, how calling works, what += means, and so on).
Somehow JSX seems to be "worst of both worlds" to me.
Some of these HTML-templates-as-code libs (like Kotlinx.html) are generated from a formal HTML specification. This is really nice, and makes it more type safe (only allow tag nesting that is allowed, and only allow attributes that are allowed; ofcourse with escape hatches).
Visual Basic .NET has XML literal support [1].
[1]: https://docs.microsoft.com/en-us/dotnet/visual-basic/program...
All these opening and closing quotes are pointless. Why don't write a single string with the verbatim html inside?