Something close to this is possible already in JS, I'm working on a library for generating HTML in node, heavily inspired by Haskell's blaze and lucid. Example code: div( { class: "table-responsive" }, table( { class: ["table table-sm", opts.onRowSelect && "table-hover"] }, thead(tr(hdrs.map(hdr => headerCell(hdr)))), tbody( vs.map(v => tr( mkClickHandler(opts, v), hdrs.map(hdr => td(typeof hdr.key === "string" ? tex…
Slightly more verbose (buying code size): https://github.com/stefanhaustein/notemplate
What if we'd had better HTML-in-JS syntax all along?
31–40 of 170 posts
Re: What if we'd had better HTML-in-JS syntax all along?
#32Example code:
div ({ class: "form-group" },
label ({ for: "exampleFormControlSelect1" }, "Example select"),
select ({ class: "form-control", id: "exampleFormControlSelect1" },
option ("1"),
option ("2"),
option ("3"),
option ("4"),
option ("5")
)
)
In conjunction with typestyle, you never have to leave js/ts. Very clean.The arguments against this approach usually boil down to the mistaken notion that "you're not separating concerns". The response is: separation of language != separation of concerns. No matter what you should still strive to reduce cyclomatic complexity. So you're still separating model, view, themes etc. And you're doing so using abstractions within the language, rather than relying on language and file boundaries. Notably in the reverse case, when you have unavoidable links between these layers (since no useful abstraction isn't leaky), the benefits of expressing everything in one language are considerable (e.g. when refactoring).
Re: What if we'd had better HTML-in-JS syntax all along?
#33 html {
body {
div {
a("https://kotlinlang.org") {
target = ATarget.blank
+"Main site"
}
}
}
}Re: What if we'd had better HTML-in-JS syntax all along?
#34Re: What if we'd had better HTML-in-JS syntax all along?
#35It’s a pity that we didn’t behold this happen.
Re: What if we'd had better HTML-in-JS syntax all along?
#36First, the word "update" doesn't appear in the article at all, and efficient and stable updates are the primary reason that client-side template systems are much more complex than their server-side string-concatenation counterparts. Updates are the main reason why you want to treat HTML as structured, because you can't map data changes to DOM changes without some knowledge of the underlying DOM structure.
Then there's no mention of E4X (or the lesser-known E4H by Ian Hixie). We've had a proposed syntax, so what went wrong and why not revive it?
Again, updates. Creating the initial DOM state isn't that bad. E4X is an incremental improvement over innerHTML. What matters is updates, and the main difference between JSX and E4X is that E4X created _new_ DOM for every invocation, while JSX is typically used to create a new _description_ of the DOM, which is applied to existing DOM to update it.
Any proposal for adding HTML syntax to JS is completely jumping the gun if it doesn't address this point. The syntax matters way less than the semantics on what such markup expressions actually evaluate to and how that result is used to update the DOM.
THen, statements like this:
> This is rubbish for obvious reasons - composing the strings is bug-prone, no typing/linting etc etc. We then have to turn them into elements with the less than elegant:
don't hold up.
lit-html[1] (I'm a maintainer) works very much like this and it excels at composition and turning markup into structured data. The complaint is very much in the vein of complaining about embedding a language into strings and saying that just programming with strings. Well, basically every programming language is just strings, with a defined grammar and tools that enforce and extract the structure. This is no different with embeddings, and JS tagged template literals were specifically designed to make embedded languages more useful.
lit-html uses the browsers HTML parser to parse the strings, enforcing that they're well-formed. It creates HTML elements that are efficiently cloned for new DOM, and it remembers where the dynamic expressions are in the DOM to efficiently update it on repeated renders. It interpolates data post-clone, so it's robust against XSS. It has a plug-ins for VS Code, TypeScript, eslint, and more, for type-checking, highlighting code-completion, and linting of templates.
Which is just to say that string-based templates are a great option that _do_ allow for fast updates, type-checking, composition, and structure, with standard syntax available today.
Finally... there are a couple of recent proposals for JavaScript that affect this area. The records and tuples proposal might make it very efficient to describe DOM in object notation. The block parameters proposal[3], though probably defunct now, proposed adding something akin to Kotlin builders, which would have allowed for the attribute/children structure we need for markup.
[1]: https://lit-html.polymer-project.org/ [2]: https://github.com/tc39/proposal-record-tuple [3]: https://github.com/samuelgoto/proposal-block-params
Re: What if we'd had better HTML-in-JS syntax all along?
#37Something close to this is possible already in JS, I'm working on a library for generating HTML in node, heavily inspired by Haskell's blaze and lucid. Example code: div( { class: "table-responsive" }, table( { class: ["table table-sm", opts.onRowSelect && "table-hover"] }, thead(tr(hdrs.map(hdr => headerCell(hdr)))), tbody( vs.map(v => tr( mkClickHandler(opts, v), hdrs.map(hdr => td(typeof hdr.key === "string" ? tex…
Interestingly, in a very early version classes were allowed to be expressed as arrays of strings just like you had, but in the vast majority of cases a space delimited string worked fine, so this feature was dropped for simplicity/uniformity.
Re: What if we'd had better HTML-in-JS syntax all along?
#38I think the JSX is just fine as an HTML-in-JS syntax. You can use JSX independently of React. Here's a 200-line library that lets you use JSX as a templating language just like Handlebars: https://github.com/wisercoder/uibuilder
What's the issue with web components that they have never took off?
Re: What if we'd had better HTML-in-JS syntax all along?
#39Laconic (https://github.com/joestelmach/laconic) is one of the oldest that I'm aware of, and suffers from some jsquery-ness:
$.el.div({'class' : 'example'},
$.el.div('content'));
Pithy (https://github.com/caolan/pithy) is another; uses function syntax to get the effect of the tag name. This was discussed previously on hn, https://news.ycombinator.com/item?id=5486239 html.div('#main', [
html.h1(null, 'Hello, world!'),
html.img({src: 'foo.jpg'})
]);
In that discussion, there are various other implementations of similar ideas - https://github.com/markgandolfo/el.js and https://github.com/insin/DOMBuilder and https://github.com/jed/domo and so on.
el.js came to my attention a long time ago, and I ended up writing a clone that I have used in my personal projects since the library almost writes itself once you steal the basic idea.Using function application is the easiest way to get the effect of TFA's syntax without the cumbersome overloading of braces.
Re: What if we'd had better HTML-in-JS syntax all along?
#40> I have a theory that a grave mistake was made in 1995 - the decision not to have a neat, succinct and declarative way of representing html elements in javascript. It may be interesting to recall that initially the only way to output HTML was by `document.write()` using strings (which was pretty declarative). The genuine way of generating HTML in JS were various methods of `String.prototype` for generating HTML form…
function MyArray() {
this.length = 0;
}
function arrayPush( value ) {
return this[this.length++] = value;
}
function arrayPop() {
return this[--this.length];
}
MyArray.prototype.push = arrayPush;
MyArray.prototype.pop = arrayPop;
var a = new MyArray();
a.push("frist");
// no console available, debug using alert()
alert( a[0] ); // "frist"
alert( a.length ); // 1
alert( a.pop() ); // "frist"
alert( a.length ); // 0