Re: [WICG/webcomponents] [templates] Ensure that template instantiation actually improves the platform (#704)

> Writing an if statement in a string attribute was never an appealing approach, and still isn’t.

Sounds similar to Vue (which adopted syntax patterns from Angular) and other systems with similar HTML-first syntax. And quite a number of people like Vue.

I like HTML-first languages too, but I can't live without the complete type support and intellisense that JSX+TypeScript offers out of the box.

I just looked at XSLT for the first time. I does remind me of Vue & Co in some ways. It also reminds me of [Alpine.js](https://alpinejs.dev/) in some ways. 

It would be as if we took Alpine.js or a similar lib, and instead of basing everything on attributes, had a more custom element approach (f.e. `<for-each>`, `<value-of>`, etc).

I believe the attribute approach is better, because I feel that custom elements are for rendering and content, not for logic. It can get tricky when such elements get in the way of CSS selectors. For example a `<value-of>` element introduced into markup would have effect on `nth-child` selectors and inadvertently break them.

I believe we need either attribute syntax, or new syntax, to avoid changing the structure of our content.

Attribute syntax is perhaps on the edge of that line (the other side being elements for logic) because it does have effect on selectors, queries, and content structure.

New syntax could _entirely_ avoid the issue (f.e. handlebars syntax for sake of example).

> So the API does not dictate how the changes should be performed and what syntax or evaluation is best for you, but it simply analyses at compile time the interpolations.

This still raises the concern: if this API is only a very low level thing, then people will make frameworks on top of it. If those new frameworks are not faster than those pushing the current boundaries like those in [`js-framework-benchmark`](https://krausest.github.io/js-framework-benchmark/current.html) and other benchmarks, then people will just use the other frameworks (with added benefits that they also work serverside without DOM APIs).

Furthermore, if a Parts API or similar becomes simply a _faster_ way to manipulate DOM, the frameworks like Solid.js/React/Vue/etc will simply use it under the hood for that purpose, while _making their code even less understandable_ in the same way that frameworks have adopted `document.cloneNode()` as a faster but less idiomatic way of creating DOM than `document.createElement()`.

So if Parts allows more speed, frameworks are gonna start writing Parts code to win in benchmarks, leading to probably insignificant gains for most people.

Back in the day, Backbone.js+Handlebars was perfectly fine for most use cases as far as performance was concerned; we accomplished most things back in the day on _slower_ hardware using those tools, and _people were ok_, while appropriate escape hatches were used when needed.

React got faster, but the real win was the developer experience improvement.

If `Parts` is only going to speed things up a small amount, but require more complicated code, leading to only framework authors using it, then it doesn't seem so valuable with the cost of its API surface area.

---

If this is going to work, IMO, it needs to provide a **_really_ good DX (dev experience)** that can compete with the status quo.

In its current state, if frameworks will merely use it for small speed gains, it will be quite a lot of engineering effort for almost nothing.

In its current state, if it will not provide any perf gain over `cloneNode` + `setAttribute` + set JS props approaches (noting that it currently does not provide a better DX), then it may end up as wasted engineering effort.

---

Keep in mind that we can write dependency-tracking reactivity systems like those that [Solid.js](https://www.solidjs.com/), [MobX](https://mobx.js.org), [Knockout](https://knockoutjs.com/), and [Vue](https://npmjs.com/@vue/reactivity) have, in [85 lines of code](https://github.com/trusktr/solid-as/blob/fd459b69424b9b16103e2cb4450952c135290577/src/signal.ts).

I can pull that out of my back pocket in any app and have a great developer experience for manipulating DOM:

```js
import {createSignal, ccreateEffect} from './file-with-85-loc'

const el = document.cloneNode(template)
const countSpan = el.querySelector('span[\\:text=count]') // f.e. <span :text="count"></span>
const count = createSignal(0)

setInterval(() => count.set(count.get() + 1), 1000) // increment every second

// This block of code reruns any time `count` changes
createEffect(() => {
  countSpan.textContent = count.get()
})

// Now the DOM updates every second.
```

This dependency-tracking reactive pattern is cleaner, and greatly improves simplicity of code bases (I haven't covered that here, but an article is coming soon).

So what does `Parts` *really achieve* that will cause people to really want to use it?

> I feel like this could be a good middle ground as frameworks can provide whatever DX they want, leaving the low level mechanism to browsers.

They indeed could! But there would need to be a benefit. Better performance for end users?

For example, why would Solid.js adopt it under the hood?

Solid.js already compiles JSX templates to the same type of code as I wrote in the previous example, plus it provides a runtime [`html`](https://github.com/solidjs/solid/tree/12b969d36e3db7eb93c9449208ad926fcc9b833f/packages/solid/html) template string tag that compiles html syntax with interpolations (same syntax as [`lit-html`](https://lit.dev/docs/v1/lit-html/introduction/) essentially) to the same sort of above code output at runtime for projects without build tools.

The DX these frameworks have _are already good_. So there'd need to be a strong reason to adopt it.

What is that reason?

> it supports SSR and it’s easy enough for browsers to implement

Would this require a DOM polyfill in Node.js? DOM polyfills ([`jsdom`](https://github.com/jsdom/jsdom), [`undom`](https://github.com/developit/undom), etc) have been proven to be slow compared to the fastest frameworks in benchmarks (by considerable margins) making the use of string interpolation/concatenation.

The slow speed of fake DOM in Node.js could be another reason that libs will avoid the `Parts` API for SSR, and hence will support their own system rather than multiple.

> It also gives us something like Solid or Svelte but at runtime (compile runtime actually), rather than having to use a compiler.

Check out [Solid's `html` template tag, using no build tools, on CodePen](https://codepen.io/trusktr/pen/XWEPezL?editors=1000). The code:

```html
<style>
 html, body { font-size: 1.5rem; }
</style>

<script type="module">
 import {createSignal, createEffect} from 'https://cdn.skypack.dev/solid-js@1.4.8';
 import {render} from 'https://cdn.skypack.dev/solid-js@1.4.8/web';
 import html from 'https://cdn.skypack.dev/solid-js@1.4.8/html';

 const [count, setCount] = createSignal(0)

 setInterval(() => setCount(count() + 1), 1000)

 const div = html`
  <div>
   <strong>Hello</strong>&nbsp;
   <em>you!</em>

   <p>The count is: ${count}</p>
  </div>
 `

 console.log(div instanceof HTMLDivElement) // true

 document.body.append(div)
</script>
```

What is the `Parts` API going to improve in that demo, for example?

-- 
Reply to this email directly or view it on GitHub:
https://github.com/WICG/webcomponents/issues/704#issuecomment-1218526858

You are receiving this because you are subscribed to this thread.

Message ID: <WICG/webcomponents/issues/704/1218526858@github.com>

Received on Wednesday, 17 August 2022 21:57:48 UTC