15 comments

[ 2.7 ms ] story [ 24.7 ms ] thread
The piece that I don't like about this is trying to standardize how to "spell" setting attributes, properties, and events in a single namespace by using sigils. JavaScript isn't Perl or K and the whole `@` vs. `.` vs `?` feels alien to the language (in my opinion). It also doesn't feel like something that could be used correctly by a component author who wanted to pass props _through_ the component they own to another component they don't.

I would expect to use something more like namespaces, where the default would be shorthand `on:`, `attr:`, `prop:`, `propOrAttr:` (maybe this is the default?) but where an explicit namespace declaration could move them if you for whatever reason needed to support XHTML 5.1 and your document already used the `on:` namespace for something else (not that _that_ is a thing right now, but why not be prepared?)

Kudos to the large text. I was thinking of doing similar on my blog.
I don't understand why Svelte isn't even mentioned. Its syntax is more readable for me.

  <div>
    {#each colors as color, i}
      <button
        style="background: {color}"
        aria-label={color}
        aria-current={selected === color}
        onclick={() => selected = color}
      >
        {i + 1}
      </button>
    {/each}
  </div>
My favorite templating library has always been amrita[0]. I really don't like template languages that try to mix code and elements into a single block of text. It mixes together two concerns and creates exceptionally fragile blobs that generally need to be fully rewritten to extend their functionality. Whereas with amrita you can generally keep the two entirely separate which makes a huge difference in practice.

These PHP style template ideas I have never understood. I thought we all agreed 30 years ago that while exceptionally functional for a "quick and dirty" approach they are horrible for long term product or application development.

You have a DOM. Use it as such.

[0]: https://github.com/rud/amrita

> Nested function calls (like React's createElement() or Hyperscript's h()) or object-based builder-style APIs just don't look enough like HTML.

What is "enough" here? It is good enough for the unified community. I know npmtrends.com isn't the best metric, but unified is popular. Unified has made it trivial to move between HTML, MDX, MD, JSX and even combinations of the above. I'm learning it's an opinion, but hyperscript and hast are HTML enough being that they're models of HTML

Hooking into a tagged template is a challenge. Functions will receive a list of unparsed html strings and already evaluated expressions to zipper up themselves before forwarding to the downstream template API.

https://stackoverflow.com/questions/39971088/evaluating-temp...

Unlike an expression or tag, a developer can hack on any AST or hyper script provided by a library. Im not sure proxies or reflection are useful working with string primitive and they're unergonomic.

This was something I mentioned on the other post so I appreciate seeing it called out clearly in the reply. (Not to assume I inspired the mention.) Thank you for sharing.

I think I've cracked this [1]. A lot of the popular frameworks just copy each other by using funky attributes, templating hacks, and compilers. You don't need that (yes, they have certain positives and negatives but you don't need them).

Instead, what's hinted at in this article (using a plain HTML string) works great. Add in a little abstraction for the sake of structure and simplicity and you've got a surprisingly robust UI framework without a ton of complexity.

[1] https://cheatcode.co/joystick (a full-stack JS framework that has its own components API)

(comment deleted)
It should be secure by default, no more .innerHTML = user_name and gluing strings together like with SQL in the '90s
After trying a bunch of ways of creating client-side apps, I've now also settled on using lit-html (not even the full Lit framework). Just the `html` and `render` functions. It's simple, convenient, and fast.

Since it "caches" the rendered parts, I haven't had performance issues just re-rendering everything on state changes (with some basic scheduling). I find it easier to reason about than React since I can use Vanilla JS everywhere, and components are just functions using the `html` tagged template, which can be composed.

(comment deleted)
Good writeup. I am in the camp that Tagged Template Literals are the ultimate answer for easy templating that is native to JavaScript. The bit about using native Signals with them is spot on too. Nothing else really allows the clean separation of HTML strings with other random JavaScript objects and pieces as easily as Tagged Templates do. On the remarks about fear of strings, server-rendered markup is just one giant string sent to the browser anyways. I don't know why some people get so worked up about why they think templates should not be strings. That is literally what HTML shipped to the browser is. It's also the easiest and most straightforward way to define templates in native JavaScript without any compile step.

I did many of my own experiments with templates that are native JS with no compile step, and reached basically the same conclusion as this post. Use tagged templates and keep it simple. My angle was server-focused, with async bits in a template doing automatic streaming while server rendering with them. Works super well and it takes so little code to achieve. Check it out if you're interested: https://www.hyperspan.dev/ or the CodeSandbox demo: https://7lpdpl.csb.app/

My biggest criticism of this design is that the author doesn't seem to have explored how Svelte, Vue Vapor or SolidJS work at all. The design seems largely based on the idea that rendering the template is a cheap operation, and that it can be done repeatedly whenever values change. So it's fine to have something like html`<div>${arr.map(el => html`...${el}...`)}</div>`, because each time the array changes, rendering every item in the list is a cheap operation. And it's typically cheap because it's rendering to a VDOM-like structure, and the more expensive diffing happens later.

But modern signal-based frameworks tend to work on the basis that doing these of rendering for each change is unnecessary, and so you should only update the relevant part of the DOM. This means rendering as seldom as often, in particular when handling conditionals and lists. This is why both SolidJS and Vue Vapor both have helpers for rendering lists and conditional elements, because if you just use `.map` and the ternary operator, things aren't going to work as you'd expect. Svelte has its own syntax but in principle works very similarly.

This proposal feels like it's very oriented around the React/Lit VDOM mechanism, with a handful of Preact-like concessions to signals where they are relatively easy to retrofit into a VDOM-like system. The problem is that these sorts of frameworks are heavyweight, slow, cumbersome things, because they're doing so much extra work. Codifying that sort of inefficiency directly into the browser seems like a terrible idea.

My second biggest criticism of this proposal is that I'm really struggling to see the benefit of it, i.e. who it's for. It can't be for framework compatibility, because it's not addressing any of the issues that actually make frameworks incompatible with each other (different state/context mechanisms, different lifecycles, etc). It can't be to codify common rendering idioms and optimise them by letting the browser implement them natively, because, as discussed, the proposal doesn't leave a lot of room for well-optimised frameworks. So I guess the idea is to ensure that the browser has a built-in web framework to make it easier for people to build complex web applications without needing to import lots of dependencies.

But if you're building a complex web application, the sort that needs specialised rendering like this, the overhead of a web framework is probably pretty minimal anyway. And if you're building simpler sites with minor interactivity, this sort of rendering system is complete overkill. You'd be better if writing a wrapper around document.createElement and going from there.

I really don't expect anybody can contribute anything more to this topic. Too many people spent their brain cycles on this already. Just roll the dice and pick any existing one. It cannot be significantly worse or better.