Live data from Hacker News

What if we'd had better HTML-in-JS syntax all along?

leontrolski.github.io

31–40 of 170 posts

Re: What if we'd had better HTML-in-JS syntax all along?

#31
post #30

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

I really like specifying event handlers with functions, I've got to see if I can get that to work with server side generated HTML.

Re: What if we'd had better HTML-in-JS syntax all along?

#32
In solenya it's very terse - you can use the HTML to JS converter to see the translation is pretty straightforward: https://www.solenya.org/convert

Example 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?

#36
This article has a number of problems: it doesn't take into account the primary reason for approaches like VDOM, the history of HTML-in-JS proposals, or the current state-of-the-art in HTML-in-JS.

First, 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?

#37

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…

Solenya does pretty much exactly what you've described: https://github.com/solenya-group/solenya

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?

#38

I 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?

They have taken off. They're widely used for enterprises and design systems, and currently used on ~8% of all page views in Chrome.

Re: What if we'd had better HTML-in-JS syntax all along?

#39
An interesting native approach; there have been library-based approaches to this that date back a while.

Laconic (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…

So, if initially there were no Array nor Object constructors (there were arrays and objects, but only prepopulated ones, representing anchors, forms, etc, found in the document), how were arrays done in a script?

  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
Post reply on HN