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/
The templates look basically identical. html-tagged template literals that support streaming and async values and automatically escape values.
What Koa does will allowing strings by be returned with a default HTML mimetype is security malpractice, IMO. It's way to easy to just interpolate user-controlled values.
vlucas · 4h ago
Wow that is uncanny. We arrived at almost exactly the same solution and started working on it at almost exactly the same time. I went a little bit further with client islands, file-based routing, custom placeholders for async loading content in templates, etc. since I was looking to replace my own use of Next.js. But man. So close to the same thing. Small world. Cheers!
jfagnani · 3h ago
Very uncanny! I like it :)
I even have a lot of those things planned, just not enough time!
I didn't do anything that required client-side JS yet, but the first things on that list are out-of-order rendering; watch mode (page reload); and hot module replacement.
vlucas · 32m ago
I checked your approach. My first attempt looked a lot like yours, but I used an AsyncGenerator. Then I benchmarked it and found out it was slow as heck so I started thinking about other ways to do it.
Iterables/Generators seem like they work well for this problem and it's the first thing I reached for too, but out-of-order streaming is really hard to do with the generator yield syntax. You have to yield things one by one as they come in, and you can't await or you're back to a slow AsyncGenerator. I wound up radically simplifying my template function to just return { content: string, asyncContent: Promise[] } instead and then made different render strategies that handle the resolution of the asyncContent differently: https://github.com/vlucas/hyperspan/blob/main/packages/html/...
I'd love to chat about the approach I used. My email is on my website.
polyrand · 7h ago
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.
maxloh · 8h ago
I don't understand why Svelte isn't even mentioned. Its syntax is more readable for me.
Author here. I could include Svelte, but honestly it's still like the others: markup with embedded binding expressions and control flow. It would only bolster my claim that popular template syntaxes are similar.
roywiggins · 8h ago
I'm somewhat partial to Alpine, which sort of crams it into html.
x-anything is just painful like Angular. UI state is better off being non-declarative, otherwise the builtin behaviors become a limit and unmaintainable workarounds ensue.
Nobody wants to express complex conditions all around the UI when derived state can be handled in a single store.
cluckindan · 7h ago
I think you meant to use color in a variable interpolation instead of ”red”. Now the code only makes red buttons.
maxloh · 7h ago
Yeah, you're right.
The code came directly from Svelte's official tutorials. Looks like I accidentally copied the problem instead of the solution!
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.
bevr1337 · 8h ago
> 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.
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.
jfagnani · 7h ago
Author here: Those don't look like HTML enough because they're not markup. Every single one of the top frameworks uses markup with interpolations as their basic template format: React, Vue, Angular, Preact, Lit, Svelte, Solid, Quik, Stencil, Marko, Polymer, FAST, and on and on.
Frameworks and rendering libraries that don't have a markup-based template syntax are just very rare.
And I think for understandable reasons: Markup-based templates look like the output, and web developers know HTML, so the templates are easier to read and write.
That StackOverflow question seems unrelated because it's asking about untagged template literals. With tagged template literals, depending on the return type, you can absolutely get to the underlying values.
bevr1337 · 7h ago
> That StackOverflow question seems unrelated because it's asking about untagged template literals.
The first answer reinvents tagged templates and the second suggests them. I thought it was a good example to show the complexity of hacking in this approach. I'll add more context in the future.
I'm agreed that the average developer would hate working with an an AST -- JSX covers 99.9% use-case and React codebases are full of functional programming escape hatches -- but it is the foundation. An HAST is an interoperable, extendable representation we can move between any framework or tooling.
I'm likely projecting too much on the proposal. Templating is the top priority but it's the ancillary bits you mention that excite me most.
> Markup-based templates look like the output
I made the mistake of drinking functional programming laced koolaid, so in my mind they really do translate well, but I respect that you have a broader perspective.
Thanks for taking the time to reply. I'm a smidge honored that you'd even review my feedback!
svieira · 9h ago
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?)
jfagnani · 7h ago
Author here. Property and event disambiguation syntax is definitely far on the easy to change side of things.
I personally think the sigils are easier to read and write than perfixes, and these particular sigils have popped up independently in multiple libraries like Vue, Lit, and LighterHTML.
But this API could use prefixes, or like Vue, it could support both.
rglover · 8h ago
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.
At a glance, this seems like a clone of React with react-router v6. How is it different?
rglover · 7h ago
Not really like React at all (and certainly not React Router). Not sure how you made that connection...
The component method in the framework is inspired by React v1 (really just that it's a function you call—my approach to everything else is different), but all of the routing is on the server-side (a light abstraction that maps back to Express.js routes).
cluckindan · 7h ago
Maybe it was the lifecycle hooks. :)
rglover · 6h ago
If you're going to evaluate a piece of technology at least take the time to play with it. This isn't just unhelpful to me, it's doing a disservice to yourself (assuming that I've created something that will help you and improve how you do your work).
cluckindan · 6h ago
Sorry, I’m on vacation and only have my phone with me. I will check it out later for sure!
MrJohz · 5h ago
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.
throwitaway1123 · 4h ago
> This is why both SolidJS and Vue Vapor both have helpers for rendering lists and conditional elements
Haven't these tagged template libraries coalesced around the html`<${SomeComponent}><//>` syntax for custom components (including control flow components like Solid's `For` component)? The readme for Ryan Carniato's Lit DOM Expressions library includes this example for instance [1]:
The author of the article mentions this very briefly, where he writes "For JSX-style references you would need to use binding syntax like <${MyComponent}>". The Preact author's htm tagged template library uses this convention as well [2].
The syntax exists, yes, but the intention of the proposal seems to be that users will use standard JS conditional/looping constructs, and even pushes this as one of the reasons that this style of template works so well here. But these are exactly the type of constructs that you need to avoid if you want fine-grained reactive DOM updates.
throwitaway1123 · 2h ago
JSX was also created with the intention of using traditional conditional/looping constructs, but that hasn't stopped Solid and Preact from repurposing it for fine grained reactivity. Preact's signal implementation has Solid-like Show/For components [1].
I won't speak for the author of the proposal, but given that Lit itself has special control flow mechanisms for conditionals and loops (the cache and repeat directives respectively [2][3]), I can't imagine the proposal being too opposed to these mechanisms.
I'm sorry, I don't think I'm being clear enough because we keep on talking past each other here.
jfagnani · 4h ago
I've definitely explored how those frameworks work, and I've written several signals integrations for Lit.
My claim, having done that, is that template re-rendering and fine-grained reactivity are entirely compatible, and neither takes away from the other.
Template re-rendering is incredibly cheap, and not at all like React/vdom. It does a few simple checks: 1) that the new template is the same as the last, 2) it runs through the linear list of values and compares them to the last, writing them if they changed. This isn't like VDOM which has to traverse two fine-grained vdom trees comparing for differences. Many huge web applications like Photoshop, Reddit, and parts of YouTube use template re-rendering.
And signals work great with this. If your template is "signal pure" then it never needs to re-render. If it's partially signals and partially non-signal data, then it only needs to re-render when non-signal data changes.
Signals are great, but signal-only systems require that all data be wrapped in them. And I have seen large apps have problems with the memory overhead of the automatic dependency tracking and change detection at each composed signal in the graph. Memory pressure and GC could be problematic for the TC39 signals proposal (though hopefully not).
To answer your next point about who this is for: lots of different audiences.
First is plain web devs. I've seen in multiple large dev orgs moves to standardize all DOM creation outside of frameworks on lit-html or something similar, mainly out of security concerns. But templated DOM creation is so common, that it's really a big whole in the web platform that it's not built in. The only reason it's not is that platform maintainers are afraid of stepping on the toes of frameworks. I don't think that's a good reason.
Second is frameworks. Whether or not the exact set of current frameworks migrate to this, a framework created for a platform with templating built-in would have a high probably of just using it instead of rolling their own. You can easily imagine a React-alike built on top of this API, as I've seen people do with lit-html. That reduces code size and increases perform for libraries and users.
Third is web components authors. Many reach for something like Lit main for the templating. I don't think they should have to, even as the maintainer of Lit. Vanilla web components + native templating takes care of a large amount of component concerns for those developers.
Fourth is the platform itself. Part of my reason for working on this proposal now as opposed to my usual "I'll get to that one day" tasks is because I've seen so many people ask for an HTML-based templating solution, ie a better `<template>`. I support that, but I don't think we can easily get there all at once. This is an attempt to build the story and capabilities for the subset of features that an JS API needs first so that the infrastructure can be used for HTML templates. If the JS API gets in, then the HTML API can reuse it, adding the expressions, scopes, control flow, etc., that HTML needs and JS doesn't.
MrJohz · 2h ago
> Many huge web applications like Photoshop, Reddit, and parts of YouTube use template re-rendering.
Those examples do not seem like ringing endorsements of this technique!
For basic functionality - when the template stays the same - I can see how this would be reasonably efficient. But inevitably you're going to end to rendering conditionals or loops, and that surely causes problems. For example, consider an array of signals. We use `.map` in a template to loop over the elements of the array and render something for each element. Now we append a new element to the array. How does this system ensure that only this new element gets rendered, without any of the other entries bring rerendered as well.
> First is plain web devs.
The security concerns are legitimate, but a full templating system is an overkill of a solution. Why not focus on those specific needs? The easiest system would be a simpler way to create and update DOM nodes dynamically, that bakes security into the system from the start - something like hyperscript that allows attributes and properties to be set, but handles escaping correctly.
> Second is frameworks.
Do you have any evidence that frameworks will want to standardise onto this, or that it will be in any way beneficial (beyond the vague feeling that there's more standardisation happening so things must be better)? There are such significant differences between frameworks even in terms of simple things like when a render or DOM update happens that it's difficult to see where frameworks would get value from a tool like this. Creating DOM nodes from scratch isn't that difficult!
> Third is web components authors.
Extending this to application devs in general, because the point about web components seems original to everything else here: is this not just picking an arbitrary framework and embedding it into the browser? That feels like if Python decided that Flask was the best web framework and decided to add it to the standard library: very convenient for those using Flask, but from then on a continual burden for anyone maintaining the language. And much like how Flask has become increasingly obsolete in Python's new asyncio world, what stops this templating mechanism from going from useful to just a new maintenance burden for browsers? And keep in mind how much has changed for frontend frameworks just in the last five years or so. Is right now really the right moment to standardise?
> Fourth is the platform itself.
It would certainly be nice if the platform had some sort of templating mechanism. There's a lot of other stuff that would be great as well. But continually adding features makes existing browsers harder to maintain, and new browsers harder to develop. There has to be some measure of balance here between the myriad of "nice to haves" and the constant increase in complexity and surface area.
Especially here, this feels like standardisation in the XKCD sense: it's not great that there's a bunch of competing frameworks, but adding a new one to the mix won't solve that problem. What's particularly irritating here is that you reference an example where standardisation has been done much better: the signals proposal was started after a bunch of libraries and tools had already demonstrated the value of signals, and formed some clear patterns that were near-universal. There was a specific need for interoperability (because otherwise different signals implementations cannot interact with each other), and the developers of the various signal libraries were involved pretty much from the start.
This feels very different from that process! Here, the differences between different favourite is far, far greater, interoperability is much less important, and it doesn't look like there's been much input at all from the developers of those other frameworks.
hk1337 · 8h ago
Kudos to the large text. I was thinking of doing similar on my blog.
RadiozRadioz · 9h ago
I think it would look a lot like XSLT
righthand · 7h ago
I got into XSLT after the HN grug brain article last week. It is wonderful and I have my whole site (100 pages/files) migrated in less than an hour (w/o using LLM) and have it served off a 4 line caddy file.
Seriously browsers just need to adopt XSLT 3.0 and stop all this wheel reinvention already.
monknomo · 7h ago
That sounds interesting, and I'd like to hear more
righthand · 6h ago
Well it’s all in a single directory:
```
static/
js/
css/
log/
my-post.xml
my-post.xsl
index.html
```
Caddyfile:
```
:8080
try_files {path}.xml {path}.html
file_server {
index index.xml index.html
root static
}
```
XSLT work is all based off of a repository someone wrote with a grug brain explainer:
The next step is to generate all of the `static` dir from markdown files and probably a new markdown-like format for registering templates to generate xsl/xml files for special html blocks and template parts or generating blog listing pages.
LegionMammal978 · 7h ago
Eh, I also thought that at one point (regarding XSLT 3.0), but it turns out that parts of it are an underspecified mess. E.g., you can specify static parameters to be supplied to the document, but it has nothing on when or how any type-conversion errors would be signaled [0]. And in general, it has very imperative features like shadow attributes that purists would turn up their noses at. I don't see it becoming widespread anytime soon.
It should be secure by default, no more .innerHTML = user_name and gluing strings together like with SQL in the '90s
jfagnani · 7h ago
This API is definitely secure by default, and that's one of the constraints and requirements I mention in the post.
The API is secure because it separates static developer controlled strings from dynamic and possibly user-controlled values by JavaScript syntax. Values from text bindings are written to the DOM by setting TextNode.data, which escapes the value first.
timewizard · 8h ago
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.
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/
The templates look basically identical. html-tagged template literals that support streaming and async values and automatically escape values.
What Koa does will allowing strings by be returned with a default HTML mimetype is security malpractice, IMO. It's way to easy to just interpolate user-controlled values.
I even have a lot of those things planned, just not enough time!
I didn't do anything that required client-side JS yet, but the first things on that list are out-of-order rendering; watch mode (page reload); and hot module replacement.
Iterables/Generators seem like they work well for this problem and it's the first thing I reached for too, but out-of-order streaming is really hard to do with the generator yield syntax. You have to yield things one by one as they come in, and you can't await or you're back to a slow AsyncGenerator. I wound up radically simplifying my template function to just return { content: string, asyncContent: Promise[] } instead and then made different render strategies that handle the resolution of the asyncContent differently: https://github.com/vlucas/hyperspan/blob/main/packages/html/...
I'd love to chat about the approach I used. My email is on my website.
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.
Nobody wants to express complex conditions all around the UI when derived state can be handled in a single store.
The code came directly from Svelte's official tutorials. Looks like I accidentally copied the problem instead of the solution!
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.
Frameworks and rendering libraries that don't have a markup-based template syntax are just very rare.
And I think for understandable reasons: Markup-based templates look like the output, and web developers know HTML, so the templates are easier to read and write.
That StackOverflow question seems unrelated because it's asking about untagged template literals. With tagged template literals, depending on the return type, you can absolutely get to the underlying values.
The first answer reinvents tagged templates and the second suggests them. I thought it was a good example to show the complexity of hacking in this approach. I'll add more context in the future.
I'm agreed that the average developer would hate working with an an AST -- JSX covers 99.9% use-case and React codebases are full of functional programming escape hatches -- but it is the foundation. An HAST is an interoperable, extendable representation we can move between any framework or tooling.
I'm likely projecting too much on the proposal. Templating is the top priority but it's the ancillary bits you mention that excite me most.
> Markup-based templates look like the output
I made the mistake of drinking functional programming laced koolaid, so in my mind they really do translate well, but I respect that you have a broader perspective.
Thanks for taking the time to reply. I'm a smidge honored that you'd even review my feedback!
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?)
I personally think the sigils are easier to read and write than perfixes, and these particular sigils have popped up independently in multiple libraries like Vue, Lit, and LighterHTML.
But this API could use prefixes, or like Vue, it could support both.
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)
The component method in the framework is inspired by React v1 (really just that it's a function you call—my approach to everything else is different), but all of the routing is on the server-side (a light abstraction that maps back to Express.js routes).
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.
Haven't these tagged template libraries coalesced around the html`<${SomeComponent}><//>` syntax for custom components (including control flow components like Solid's `For` component)? The readme for Ryan Carniato's Lit DOM Expressions library includes this example for instance [1]:
The author of the article mentions this very briefly, where he writes "For JSX-style references you would need to use binding syntax like <${MyComponent}>". The Preact author's htm tagged template library uses this convention as well [2].[1] https://github.com/ryansolid/dom-expressions/tree/7fd9f86f1b...
[2] https://github.com/developit/htm
I won't speak for the author of the proposal, but given that Lit itself has special control flow mechanisms for conditionals and loops (the cache and repeat directives respectively [2][3]), I can't imagine the proposal being too opposed to these mechanisms.
[1] https://github.com/preactjs/signals/blob/eae850a9f3aa62e505a...
[2] https://lit.dev/docs/templates/conditionals/#caching-templat...
[3] https://lit.dev/docs/templates/lists/#the-repeat-directive
My claim, having done that, is that template re-rendering and fine-grained reactivity are entirely compatible, and neither takes away from the other.
Template re-rendering is incredibly cheap, and not at all like React/vdom. It does a few simple checks: 1) that the new template is the same as the last, 2) it runs through the linear list of values and compares them to the last, writing them if they changed. This isn't like VDOM which has to traverse two fine-grained vdom trees comparing for differences. Many huge web applications like Photoshop, Reddit, and parts of YouTube use template re-rendering.
And signals work great with this. If your template is "signal pure" then it never needs to re-render. If it's partially signals and partially non-signal data, then it only needs to re-render when non-signal data changes.
Signals are great, but signal-only systems require that all data be wrapped in them. And I have seen large apps have problems with the memory overhead of the automatic dependency tracking and change detection at each composed signal in the graph. Memory pressure and GC could be problematic for the TC39 signals proposal (though hopefully not).
To answer your next point about who this is for: lots of different audiences.
First is plain web devs. I've seen in multiple large dev orgs moves to standardize all DOM creation outside of frameworks on lit-html or something similar, mainly out of security concerns. But templated DOM creation is so common, that it's really a big whole in the web platform that it's not built in. The only reason it's not is that platform maintainers are afraid of stepping on the toes of frameworks. I don't think that's a good reason.
Second is frameworks. Whether or not the exact set of current frameworks migrate to this, a framework created for a platform with templating built-in would have a high probably of just using it instead of rolling their own. You can easily imagine a React-alike built on top of this API, as I've seen people do with lit-html. That reduces code size and increases perform for libraries and users.
Third is web components authors. Many reach for something like Lit main for the templating. I don't think they should have to, even as the maintainer of Lit. Vanilla web components + native templating takes care of a large amount of component concerns for those developers.
Fourth is the platform itself. Part of my reason for working on this proposal now as opposed to my usual "I'll get to that one day" tasks is because I've seen so many people ask for an HTML-based templating solution, ie a better `<template>`. I support that, but I don't think we can easily get there all at once. This is an attempt to build the story and capabilities for the subset of features that an JS API needs first so that the infrastructure can be used for HTML templates. If the JS API gets in, then the HTML API can reuse it, adding the expressions, scopes, control flow, etc., that HTML needs and JS doesn't.
Those examples do not seem like ringing endorsements of this technique!
For basic functionality - when the template stays the same - I can see how this would be reasonably efficient. But inevitably you're going to end to rendering conditionals or loops, and that surely causes problems. For example, consider an array of signals. We use `.map` in a template to loop over the elements of the array and render something for each element. Now we append a new element to the array. How does this system ensure that only this new element gets rendered, without any of the other entries bring rerendered as well.
> First is plain web devs.
The security concerns are legitimate, but a full templating system is an overkill of a solution. Why not focus on those specific needs? The easiest system would be a simpler way to create and update DOM nodes dynamically, that bakes security into the system from the start - something like hyperscript that allows attributes and properties to be set, but handles escaping correctly.
> Second is frameworks.
Do you have any evidence that frameworks will want to standardise onto this, or that it will be in any way beneficial (beyond the vague feeling that there's more standardisation happening so things must be better)? There are such significant differences between frameworks even in terms of simple things like when a render or DOM update happens that it's difficult to see where frameworks would get value from a tool like this. Creating DOM nodes from scratch isn't that difficult!
> Third is web components authors.
Extending this to application devs in general, because the point about web components seems original to everything else here: is this not just picking an arbitrary framework and embedding it into the browser? That feels like if Python decided that Flask was the best web framework and decided to add it to the standard library: very convenient for those using Flask, but from then on a continual burden for anyone maintaining the language. And much like how Flask has become increasingly obsolete in Python's new asyncio world, what stops this templating mechanism from going from useful to just a new maintenance burden for browsers? And keep in mind how much has changed for frontend frameworks just in the last five years or so. Is right now really the right moment to standardise?
> Fourth is the platform itself.
It would certainly be nice if the platform had some sort of templating mechanism. There's a lot of other stuff that would be great as well. But continually adding features makes existing browsers harder to maintain, and new browsers harder to develop. There has to be some measure of balance here between the myriad of "nice to haves" and the constant increase in complexity and surface area.
Especially here, this feels like standardisation in the XKCD sense: it's not great that there's a bunch of competing frameworks, but adding a new one to the mix won't solve that problem. What's particularly irritating here is that you reference an example where standardisation has been done much better: the signals proposal was started after a bunch of libraries and tools had already demonstrated the value of signals, and formed some clear patterns that were near-universal. There was a specific need for interoperability (because otherwise different signals implementations cannot interact with each other), and the developers of the various signal libraries were involved pretty much from the start.
This feels very different from that process! Here, the differences between different favourite is far, far greater, interoperability is much less important, and it doesn't look like there's been much input at all from the developers of those other frameworks.
Seriously browsers just need to adopt XSLT 3.0 and stop all this wheel reinvention already.
```
static/
```Caddyfile:
```
:8080
try_files {path}.xml {path}.html
file_server {
}```
XSLT work is all based off of a repository someone wrote with a grug brain explainer:
https://github.com/pacocoursey/xslt
The next step is to generate all of the `static` dir from markdown files and probably a new markdown-like format for registering templates to generate xsl/xml files for special html blocks and template parts or generating blog listing pages.
[0] https://github.com/Paligo/xee/issues/32#issuecomment-2762343...
The API is secure because it separates static developer controlled strings from dynamic and possibly user-controlled values by JavaScript syntax. Values from text bindings are written to the DOM by setting TextNode.data, which escapes the value first.
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