Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DOM parts use outside of <template> seems unlikely #1035

Open
matthewp opened this issue Nov 7, 2023 · 55 comments
Open

DOM parts use outside of <template> seems unlikely #1035

matthewp opened this issue Nov 7, 2023 · 55 comments

Comments

@matthewp
Copy link

matthewp commented Nov 7, 2023

As currently proposed, DOM parts makes it easier to build templating solutions using <template>. However, in reality, most templating solutions are intended to be used both in the client and on the server to produce initial HTML (aka "SSR").

As such, builders of templating libraries will need to build 2 implementations, one that uses DOM parts and one that does not. This makes the proposal a dead-end in my opinion. Most templating libraries will choose to build one solution that works in both contexts.

Given the amount of work needed to build this API, and the limited utility, it needs to be discussed if the work is worth the effort and long-term maintenance requirements.

@EisenbergEffect
Copy link

EisenbergEffect commented Nov 7, 2023

I don't think templating libraries will need two implementations.

Once there's a standard, there will be a common API that anyone can build on top of. I would expect this to be implemented in a variety of ways. Certainly, as part of DOM libraries like JSDOM, but likely in standalone form as well. The declarative syntax should be pretty straight forward to both generate and parse.

Note that SSR scenarios, both inside and outside of template elements, are a key requirement of the API that was laid out during the initial discussions.

I just want to make sure, have you looked at both the imperative and declarative proposals?

@matthewp
Copy link
Author

matthewp commented Nov 7, 2023

Yes I have.

@bahrus
Copy link

bahrus commented Nov 8, 2023

As I understand it, currently, the primary purpose of DOM parts is not to make building templating solutions easier. That is a secondary goal.

There's an outstanding empirical question that I think is still being investigated -- is the DOM API, as it stands, completely optimized as far as being able to perform rapid updates of DOM fragments, in every possible way? If it is, then I agree, adding superfluous API's seems unlikely to be used, unless it at least improves the developer ergonomics (the secondary goal, which I have no position on whether that is the case). If it isn't, and there are some missing API's that could make the browser update the fragments faster, why would we not want to consider adding that to the platform? That is the primary mission of DOM parts. Again, if the primary mission proves to be a dud, then I agree, we should look closely at the value-add of the ergonomics of the API, and ask ourselves whether anyone outside the platform would use it.

The answer to that question has little to no bearing on whether the platform should provide built in support for templating. It was agreed a while ago, that we needed this empirical question looked into, first, as we don't want to build higher level functionality (like templating) on top of a sub optimal API. Hopefully we will know the answer soon (January?), so we can move on either way.

For server rendered 100% static HTML, these API's wouldn't be very useful, I agree (just as the existing api's, such as querySelectorAll, etc. aren't very useful). But even for extremely server-centric solutions, for example, solutions that use server sent events to update the UI, I have a hard time seeing why they wouldn't want to update the UI as fast as possible, which (we are hoping) is the primary mission of DOM parts, as I understand it.

@matthewp
Copy link
Author

matthewp commented Nov 8, 2023

If it isn't, and there are some missing API's that could make the browser update the fragments faster, why would we not want to consider adding that to the platform?

I agree, but I don't understand how this is the case of this API if you omit the template use-case. Why would updating via DOM parts be faster than calling the lower-level textNode.data = 'foo' and el.setAttribute('key', value)? It's faster if you account for traversal requirements; but traversal is a requirement of templating. Maybe I'm missing something, so I would love an explanation.

The answer to that question has little to no bearing on whether the platform should provide built in support for templating. It was agreed a while ago, that we needed this empirical question looked into, first, as we don't want to build higher level functionality (like templating) on top of a sub optimal API. Hopefully we will know the answer soon (January?), so we can move on either way.

This thread is my attempt to participate in that conversation. I was told that filing an issue was the way to do so. If not, what is?

For server rendered 100% static HTML, these API's wouldn't be very useful, I agree (just as the existing api's, such as querySelectorAll, etc. aren't very useful). But even for extremely server-centric solutions, for example, solutions that use server sent events to update the UI, I have a hard time seeing why they wouldn't want to update the UI as fast as possible, which (we are hoping) is the primary mission of DOM parts, as I understand it.

I don't understand how this proposal leads to faster updates once you know the parts that need updating. I would love to understand that better. Thanks.

@EisenbergEffect
Copy link

It may lead to faster updates, if the browser is able to batch part updates via deeper integration with its lifecycle. That's an unknown and something that the prototype is seeking to answer.

I think the traversal part is actually a benefit that framework authors want from DOM parts. With the declarative API in place, there won't be a need to traverse DOM anymore. You can simply call an API and the browser will give you the instanced template along with all the located parts in one go. This would not only eliminate code from many JS frameworks and libraries but also likely speed up the initial render times.

@otabekshoyimov
Copy link

Sorry if it is a dumb question but why dom parts (templating) proposal is only intended for client only use? Web components spec also started this way, now look where they are right now, ssring wc is a lot of work because spec didn't consider ssr in the first place. So why we are making the same mistake again? The OP is right, nobody wants to right two templating solutions for client and server. I just want to know, why spec is not considering ssr as a first class citizen? The web is not client only, but hybrid client and server

@bahrus
Copy link

bahrus commented Nov 9, 2023

Not a dumb question at all, @otabek-git. I think it fair to say people are trying to look at ssr carefully as it relates to templating, I'm not sure if we have considered all possible solutions, so any ideas are encouraged. Here's what we have so far:

  1. This is the approach that has the most "hands on deck" as far as accommodating ssr, and which looks quite promising to me.
  2. I've proposed adding first-class support for micro-data, which I believe could help with hydrating as the HTML streams in, and could also be used to infer the template from server-generated content (though the one with all hands on deck above might be more effective at that, not sure).
  3. Providing first-class support for progressive enhancement, and at the same time use the same developer code that could integrate with template instantiation would, I think, work well with ssr. That proposal also begins to quietly make the case for a "template instantiation manifest", where some bindings could be moved outside the template, and applied to server rendered content via css, similar to corset and trans-render libraries. I think there's a stronger case for that, that ties in with the proposal below:
  4. This proposal, as I see it, is the first step towards supporting "parts" in service workers as well as in remote JS-based services built with bun or deno or cloudflare workers.
  5. I'm sure there are others (these are all skewed towards things I'm following closely, as I proposed many of them).

@matthewp
Copy link
Author

matthewp commented Nov 9, 2023

@otabek-git Thanks for your input, this is exactly why I raise the issue. The goal of having a declarative way to do DOM updates is a good goal, but the solution of templating is a dead-end because it is incompatible with the way the web works.

Templating is a one-way operation, you have a template and some data and something comes out the the other end (html, text, whatever). You cannot reverse that operation. But reversing is a requirement on the web, as much of your templating has already occurred on the server.


@bahrus Thanks for bringing up that post, which I have read in the past, let's talk about it:

<section>
  <h1 id="name"><?child-node-part?><?/child-node-part?></h1>
  Email: 
  <?node-part?><a id="link"><?child-node-part?><?/child-node-part?></a>
</section>

The fact that this is the proposed solution to the problem should be a red flag for why we should not pursue templating.

  1. Does anyone think this looks, in any way, good?
  2. Would anyone want to hand-write this? The implication of going this route is that HTML becomes a compile target. Do we really want to go down that route? HTML is no longer something you write yourself?
  3. I am highly skeptical that browsers would want to modify the HTML parser in order to support this. Historically HTML parser changes have a very high bar. You can look at other issues in this repo to see proposals that require parser changes and see the reasons why they have been denied. That's not to say that it's impossible, but releasing DOM parts to later have this idea be denied for parser technical/security/whatever reasons feels like wasted time.

There are other ways to support declarative DOM updates outside of templating, and those are the things that we should be pursing. CSS is a good example of a DSL that allows modification of DOM (through its styles) while being detached from how the DOM is produced. See this blog post for a good review of CSS' potential as it continues to get better: https://bkardell.com/blog/CSSLike.html

@bahrus
Copy link

bahrus commented Nov 9, 2023

Just my hot-take, from the department of faulty analogies:

For styling, we support both inline and "styling from a distance", aka CSS. My gut tells me want to do the same for binding. Binding from a distance does have some strong use cases -- we can apply multiple layers of binding from different sources, easier to do binding in bulk, can work with third party content, etc. I think the elix library found that there's a strong need for muti layer binding as well. But the argument for things like tailwind css, locality of behavior, etc, makes me think the right solution is what my github logo is meant to represent -- embrace the duality principle, and support both.

@bahrus
Copy link

bahrus commented Nov 9, 2023

Also, I think the latest iteration may be a bit different from what you have, but nevertheless, yes, the proposal is for a kind of "compile-type" intermediate syntax in the pipeline. Maybe over time, that syntax could be handled behind the scenes in a service worker, not sure. I do see some difficult, but not insurmountable challenges to go along with it -- needing a tag helper for c#, something for php, rails, etc, that can emit that intermediate syntax. If the benefits outweigh the "costs", though, I could it see it working. If not, your concerns become stronger, so maybe it's time to take a harder look at "binding from a distance", not sure.

@matthewp
Copy link
Author

matthewp commented Nov 9, 2023

@bahrus I really like the phrase "binding from a distance" because it both captures the idea and also does so without pointing to a specific solution. So I'll be borrowing that phrase in the future, thanks a lot!

In addition to the use-cases you mentioned, the biggest advantage to "binding from a distance" is that it is agnostic of how the HTML is produced, meaning that it works with any backend. This is a critical feature of the web that we must preserve.

Templating as a solution here is heavily biased towards JS-based backends. Non-JS based backends would need to find a way to get their language to run in the frontend. If you look at what language communities are doing at present, they are not really doing this much (there are exceptions like C# Blazor), instead they are achieving equivalent abilities through RPC + DOM diffing. Phoenix LiveView, Laravel Livewire (PHP), and Ruby Hotwire are examples of solutions that do this.

For anyone advocating for DOM parts, they need to answer the question as to how a Python / Ruby / whatever backend is going to participate in these APIs.

@EisenbergEffect
Copy link

EisenbergEffect commented Nov 9, 2023

Apologies for the wall of text that follows, but I want to make sure we're all on the same page regarding the current state of the proposal, based on the last meeting I attended.

@matthewp Please make sure to read that entire post through to the end. That syntax you are showing above is not what is currently proposed. A couple points about the syntax you are showing:

  • Nobody ever wanted that syntax. It was originally thought that this was the only technical way to achieve the stated goals though. Thankfully, that has since been disproven.
  • The HTML WG doesn't want to do stuff with processing instructions, so it's already been decided that's definitely not going to happen.

The current declarative syntax is inspired by 20 years of templating languages across multiple front-end and backend technologies. It's also explicitly designed to handle SSR and be backend-agnostic. No JS code needs to run on the server in order to express fully declarative templates which include both immediately rendered server values and client-side metadata used by front-ends.

Let me just review what the basic syntax is here based on my understanding from the most recent CG meeting that I attended:

Let's say you have an <a> tag and you want to bind its href to a URL for a user record, where the url contains the id of the user. You could express that like this.

<a href="./users/{{user.id}}">...</a>

The double curly {{}} represents a DOM Part. What is between the {{ and }} at this time is up for interpretation. It is treated as metadata to be interpreted however the developer wants. In the future, there is a hope that there will be an expression syntax, but it's too early to know what that should be. The goal right now is to try to define a modular, extensible syntax skeleton. (It could even be that the metadata is some sort of id or selector that CSS could bind an expression or value to. Who knows? That's all a possibility if there's consensus around that sort of thing. The current proposal does not prevent that sort of approach.)

On the client, an API can be called on a DOM node to retrieve the tree's parts along with their metadata, so no DOM walking is needed, allowing templating engines to eliminate code and potentially improve their initial render times. From what I can tell, a lot of JS framework authors are extremely interested in the ability to mark locations in the DOM and associate metadata with those locations.

Let's look at another version of this same example, one that shows declarative SSR output:

<a href="./users/{{# user.id}}12345{{/}}">...</a>

The {{metadata}} syntax can be expanded out to {{# metadata}}value{{/}} if you want to encode both metadata and an initial value, such as one that would be rendered by a server. In the example above, the browser will render the following immediately with no JS code involved:

<a href="./users/12345">...</a>

And at the same time it will create a part and associate the user.id metadata with that part so that client code can interpret it if desired.

The syntax above is just the current proposal, used to prototype out the ideas. It can be changed. But most folks seem to be happy with it as it is inspired by very popular, long-lived libraries like Handlebars/Mustache and bears a strong resemblance to many modern templating engines.

Again, a key element of this is that no JS is involved in the above and the syntax is able to both encode server-rendered value and metadata that could be leveraged on the client.

Any server-side framework today is capable of generating output in this form. A JavaScript backend is not needed. These are key requirements of the proposal that have been stated from the beginning and considered as part of the current design. If you think there's a flaw with this, please be very concrete about the problem and make some concrete proposals for how to fix it. I think everyone very much wants to hear that feedback and is sensitive to getting this right in a way that it is broadly usable.

I also wanted to make a couple of notes about the HTML parser and browser vendor aspect of the concerns.

First, the proposal you see here is coming from browser vendors. The design has strong alignment from both WebKit and Chrome already. It originated with WebKit. Browser vendors really want to solve this problem and have a lot of motivations for doing so.

Second, WebKit has proposed a way to implement this without altering the HTML parser itself. So, that's not a real concern anymore. The parser would parse according to the normal rules. The DOM itself would make the transform after parsing, under strictly dictated conditions (the presence of a parseparts attribute on a parent DOM node). This is intended to work both in templates as well as directly in the document.

With respect to specific languages like Python/Ruby or frameworks/approaches like Laravel and Hotwire, I can only speak generally. I haven't used Laravel in a number of years and haven't ever written a Python web backend. It's been a while since I used Rails, but I do keep tabs on Hotwire and the other client/server paradigms the community is working on there. I do think this should all work very well in those context. We are talking about fully declarative syntax for all of this. It's just a matter of these frameworks sending down html that uses this syntax with the values they already have on the server. You can even use things like Hotwire/Turbo and HTMX with this. The server is free to dynamically send down HTML with this syntax at any time. If it has a parseparts attribute, it can just be shoved in the DOM like any other HTML and the browser will render the values, capture the parts, and associate the metadata automatically. This seems like it could provide some very interesting opportunities.

Ok, hopefully this helps clear up a few things. It just seemed that there was some out-of-date information. Let's continue the conversation. I'm trying to understand the concerns but am having a hard time seeing the issue with the current version of the proposal.

@matthewp
Copy link
Author

matthewp commented Nov 9, 2023

Hey @EisenbergEffect, thanks for taking the time. My issues were not about the specific syntax choice, but rather that it is a square peg in a round hole situation. Of course with enough effort you can make anything work. But is it natural to do so? Wouldn't it be better to find a round peg?

I'm happy to dig more into the proposal if you'd like. I understand what it is doing. It's similar to Alpine.js (in approach, not syntax), in that you are writing a template within a template. Writing the same thing two times with different syntax. To take one of your examples, within your host language template you'd be writing something like: <a href="./users/{{# user.id}} <%= user.id %> {{/}}">...</a>, specifying the same logic in two different templates. Things like Alpine work ok in simple scenarios but break down as complexity grows; ie doing something like a loop with sorting is difficult. Personally I do not find this example to be something I'd desire to write.

How does one then perform an update in their host language? I don't think that it's really practically possible outside of the C# Blazor approach of compiling to wasm. Most other server language communities have not gone in this direction and instead are preferring a PRC + Diffing approach. We should look as to why these languages have not followed the pattern of this proposal.

Anything is possible with enough effort, but this thread is positing that a "binding from a distance" (hat-tip to @bahrus) approach is a better fit for the same reasons that CSS is a better fit than <font>, <center> and friends.

@EisenbergEffect
Copy link

EisenbergEffect commented Nov 9, 2023

I'd love to see a concrete example of how "binding from a distance" would work. Let's just take the same example I have from above, where you've got an a tag and you want to bind part of the href value, and you need to be able to interpolate a specific value on the server while also providing the binding expression for the client. How would that manifest? Just some pseudo code or something to help me understand would be appreciated.

@matthewp
Copy link
Author

matthewp commented Nov 9, 2023

@EisenbergEffect: There are many possible DSLs one could imagine. We shouldn't limit ourselves to one specific solution. But for the sake of discussion, here's one:

index.html

<style type="bindings">
a {
  --user-id: 1234;
}
</style>
<a>...</a>

bindings.css

a {
  href: "./user/" var(--user-id);
}

script.js

el.bindings.setProperty('--user-id', newId);

Note that this is all pseudo-code, i'm not proposing this exact thing. This is meant to demonstrate that we already have something like "binding from a distance" in that we have "style from a distance".

@EisenbergEffect
Copy link

EisenbergEffect commented Nov 9, 2023

I could be misunderstanding this, but it seems this would be far more challenging for a server framework to manage, since now when someone writes an expression in their server template, the framework would have to split that out into two different files entirely. The SSR'd value would need to go into a style tag just before the element that was being generated, and the binding expression would need to be extracted into a separate CSS file. It's also not clear how this would target individual text nodes or whole elements (not necessarily an attribute), or handle block scenarios. Here's a more realistic example showing what the current proposal would support in terms of block rendering, element targeted parts, attribute interpolated parts, and text interpolated parts.

<ul parseparts>
  {{# for user of users}}
    <li {{draggable}}>
      <a href="./user/{{user.id}}">User {{user.name}} is {{user.age}} years old.</a>
    </li>
  {{/}}
</ul>

(Again, note that everything between {{ and }} is considered metadata at this point in the game. So, "for user of users" is just something I made up right now; that's just considered metadata by the browser for now.)

The CSS-like approach here also seems a bit tricky for the browser to manage because even if the SSR'd value for userId is provided in the style tag for bindings, the browser can't do anything with that until it downloads the css file that tells it what to do. I would worry that this would cause all sorts of content update flashes and potentially perf issues with needing to do a double render for almost everything. First the browser renders the a tag, and then it has to re-render it, and it has to do this across the entire DOM, potentially hundreds or thousands of nodes. When we were initially working through different options, we heard from browser vendors that it wasn't really acceptable to have bindings without values. It makes it difficult for the rendering engine to know what to do. I understand this isn't exactly the same situation, but it seems to introduce a set of related problems. This would also seem to be an issue for SEO.

Let's keep iterating. We need a concrete workable alterative if there is really dissatisfaction with the current direction. Any new proposal has to address the core set of requirements as well as the concerns that browser vendors have raised with past iterations of dom parts.

@EisenbergEffect
Copy link

EisenbergEffect commented Nov 9, 2023

As an aside, I don't know how I come across when I'm writing on a thread like this. I hope you all know that I'm not trying to be antagonistic. I genuinely want to understand the concerns and I'm really interested in seeing viable alternatives. We definitely need more diversity of thought in this area.

The one thing I do want to note is that it's very important that alternatives address the core use cases and handle any issues that browser vendors may have raised in the past with various other alternatives. I know it's hard to know about all of that if you haven't attended the meetings. That's why I bring some of it up here.

As a reminder, the core use cases that the proposal was trying to address are:

  • Template-based Client-side Rendering
  • Server-Side Rendering (SSR) with Hydration/Continuation
  • Deferred SSR
  • Declarative Custom Elements

If there are some additional use cases or constraints that the community wants added to this list, it would be great to have those stated and for someone to attend the next DOM Parts breakout and present that to the group.

@matthewp
Copy link
Author

matthewp commented Nov 10, 2023

As an aside, I don't know how I come across when I'm writing on a thread like this. I hope you also know that I'm not trying to be antagonistic. I genuinely want to understand the concerns and I'm really interested in seeing viable alternatives. We definitely need more diversity of thought in this area.

Thank you for stating this! I hope you that you see that I am also not trying to be antagonistic. I would only caution against statements like this:

Let's keep iterating. We need a concrete workable alterative if there is really dissatisfaction with the current direction. Any new proposal has to address the core set of requirements as well as the concerns that browser vendors have raised with past iterations of dom parts.

This comes across, I'm sure unintentionally, as telling people what types of feedback is and is not valid. That should not be the case. If people (myself for example), think that the requirements themselves are wrong, or that there are missing requirements, those are things we should able to talk about. In summary, don't try and box in the conversation.

I'm sure that you're trying to help by providing context for what you think browsers will accept. I would rather state my viewpoints, plainly for all to see, and be ignored, than be talked into giving a narrow feedback that only allows tweaks. My viewpoint is that templating as a solution is inherently against the core principle of the web of being server-agnostic, and that is where my feedback and counter proposal comes from.

Appreciate your willingness to discuss this and thank you for this note! 💚


Just noting that i plan on responding to this comment: #1035 (comment) but will have to do so in my free time.

@bkardell
Copy link

I'm having a little trouble reconciling a few things in my head, and I've been talking to @matthewp offline to try to get my head around it better so I'm not just adding noise.. I feel like maybe I should bring it back here at this point even if it winds up being noise in case other people are also not entirely clear.

If I understand correctly, I believe a key to @matthewp's idea is that there would just be no SSR of 'bound' data in the way that CSS also doesn't SSR.

However... I'm having difficulty reconciling: We already have the option to not SSR, but don't? Like, isn't almost everything today initially that -- but then people say "but no we also want to server render some of this" and that's where things get spicier?

@bahrus
Copy link

bahrus commented Nov 10, 2023

I just wanted to add a (possibly separate) thread to this conversation. I may turn this thought into a separate proposal after mulling it over (unless I hear that it is obviously something we would do even if I didn't propose it). Whether or not the platform decides to officially support "binding from a distance" in addition to inline binding, which is my preference, I think, as someone who is finding scenarios where binding from a distance is quite useful, that this is the most important thing -- it ties in, actually, with something I've tried to articulate, possibly with only partial success, in my custom enhancements proposal:

Hopefully, someday soon, we will start seeing concrete implementations built into the platform, via inline binding, for things like for-each. It would be great if in addition to supporting such functionality that gets triggered by the presence of inline binding via handlebar syntax, we could also programmatically attach (connect?) that functionality, i.e. something like:

oElement.bindings.attachForEach(List, repeatingTemplate, repeatingTemplateParts);

The truth is, I think, implementing a "binding from a distance" solution is fairly easy in userland, (well, some of the syntax @matthewp is showcasing, which looks really cool, might not be so easy). It's the actual heavy investment in the grunt work behind the nested looping, conditionals, etc. that (I) would want to be able to leverage "from a distance".

@tbondwilkinson
Copy link
Contributor

tbondwilkinson commented Nov 10, 2023

Hey all, thanks for the lively discussion.

I have a few thoughts.

This API has one central goal - replace clientside JavaScript and HTML markers with a browser native API. The clientside JS we are currently targeting is

  1. Code that does HTML rendering with a combination of static template content (<template>) and dynamic template content (updated via DOM APIs).
  2. Code that updates DOM that is already rendered, this includes SSR hydration. The intention here is event listeners for interactivity or other dynamic content that can only be known on the client.
  3. Code that updates DOM that has previously been rendered by either CSR as in 1 or SSR in 2.

Code that does not fall into one of those categories is interesting to us, but not the MVP that we've agreed on up to this point (we're open to changing that, if there's feedback).

I think setting HTML content via CSS is a design direction we have been discouraged from exploring, but I'm interested in it as well. There was quite a bit of pushback on the CSS toggle proposal, where people questioned why CSS was now responsible for what would normally have been the domain of HTML. I'm talking about this example:

a {
  href: "./user/" var(--user-id);
}

The DOM parts equivalent would be something like:

HTML

<div id="root" parseparts>
  <a href={{}}></a>
</div>

JS

const root = document.getElementById('root');
root.getParts()[0].node.setAttribute('href', `./user/${userId}`);

I agree it would be nice if userId there was some data variable that the browser knew about and it could referenced in CSS as well as JS. We have been ruminating about introducing a data layer (update this one JS object and the HTML is automatically re-rendered based on rendering rules that you set) as well here - but we want to deliver value first in the above use cases before we propose something bigger. That remains an open question - but one that we're interesting in exploring next.

We also explored an idea where you would pass in a data object to some DOM API to update attributes, rather than having to visit the NodePart.

I want to be clear that our focus and priority has been on figuring out the technical feasibility of this space. Is it possible for us to design an API that has reasonable performance and replaces the existing JavaScript code that we have in frameworks for rendering and updating rendered content? That's the question we've been building benchmarks for and discussing in depth with browser and v8 engineers. Because without answering that question, any discussion of API shape could be wasted time if we don't properly know what trade-offs from a performance and feasibility perspective we're up against.

@matthewp
Copy link
Author

@bahrus I have written a library that does my CSS idea here and the hard parts are 1) knowing when a selector changes and 2) the algorithm that determines which rule should apply at a given moment in time.

Things like loops etc are easy; you get those for free from CSS, since all selectors are "each" in CSS already.

@matthewp
Copy link
Author

matthewp commented Nov 10, 2023

@bkardell

However... I'm having difficulty reconciling: We already have the option to not SSR, but don't? Like, isn't almost everything today initially that -- but then people say "but no we also want to server render some of this" and that's where things get spicier?

Just noting that my example does SSR. It's just that you write the initial SSR value in the sheet rather than in the HTML. Since it's an inline sheet it is applied before paint happens, just like CSS, so there is no "flash" where the link is missing an href.

Also noting that you could, if you wanted, put the value in the HTML as well. Then when the sheet gets applied (for example if it were async loaded), it would reapply with the same value. It's just that with "binding from a distance" you are not forced to write twice, because it is decoupled. So you have more flexibility.

@matthewp
Copy link
Author

matthewp commented Nov 10, 2023

@EisenbergEffect

I could be misunderstanding this, but it seems this would be far more challenging for a server framework to manage, since now when someone writes an expression in their server template, the framework would have to split that out into two different files entirely. The SSR'd value would need to go into a style tag just before the element that was being generated, and the binding expression would need to be extracted into a separate CSS file.

You're assuming that the user is writing it with an existing templating language and the language is "compiling" it to what I wrote, but that doesn't need the be the case (although a templating could do that if it wanted)! The user would just only write the binding in the binding part, and leave the HTML part blank.

I agree though that writing an inline style "binding sheet" would be ugly, so you might want to write it this way instead:

index.html

<a data-user-id="1234">...</a>

bindings.css

a {
  --user-id: attr(data-user-id);
  href: "./user/" var(--user-id);
}

It's also not clear how this would target individual text nodes or whole elements (not necessarily an attribute), or handle block scenarios.

You can't target individual text nodes, just like you can't with CSS. As with CSS you use separate <span>s if you want to target more than one text part for binding. You might notice that most of my answers to questions are just pointing to how CSS works. That is the intent of this idea.

The CSS-like approach here also seems a bit tricky for the browser to manage because even if the SSR'd value for userId is provided in the style tag for bindings, the browser can't do anything with that until it downloads the css file that tells it what to do. I would worry that this would cause all sorts of content update flashes and potentially perf issues with needing to do a double render for almost everything. First the browser renders the a tag, and then it has to re-render it, and it has to do this across the entire DOM, potentially hundreds or thousands of nodes. When we were initially working through different options, we heard from browser vendors that it wasn't really acceptable to have bindings without values.

The values are present in the initial HTML, they just aren't present at the HTML insertion point like with templating. They are present in another place and applied. They are applied before paint, so there are no FOUC concerns here.

Think about it like with CSS. If you want some text to be red, you don't have to define it as red in the element's style attribute for it to be red. It's red because you have a blocking stylesheet or inline stylesheet. The same applies here.

@matthewp
Copy link
Author

@tbondwilkinson Thanks for joining the party. 😀

Code that does not fall into one of those categories is interesting to us, but not the MVP that we've agreed on up to this point (we're open to changing that, if there's feedback).

Consider this the feedback 🙂. I challenge you to find examples of (2) and (3) in existing userland framework that are not JS-based backends. The templating proposal is not dissimilar from how a lot of existing JS frameworks work today. But non-JS frameworks largely do not. Why is that?

I think answering this questions is the critical thing to do before proceeding further. Happy to continue this discussion in another thread if it helpful.

My belief is this: templating naturally leads one towards an "isomorphic" solution; which is a solution where the server and client environments are abstracted so that they appear (to the developer) as just one abstraction. And any non-JS language is at a disadvantageous position because it's much harder for them to present such an abstraction as those languages do not (mostly, and some with caveats) run in the browser.

I think setting HTML content via CSS is a design direction we have been discouraged from exploring, but I'm interested in it as well. There was quite a bit of pushback on the CSS toggle proposal, where people questioned why CSS was now responsible for what would normally have been the domain of HTML

I have seen such feedback before too. A CSS-like solution doesn't necessarily need to be .css, it could be a new DSL that shares the same parser but has some different constraints.

Or maybe a CSS-like is not the answer. I'm mainly trying to get people to think about "binding from a distance" as a positive thing that helps decouple. CSS is just a natural thing to pull ideas from since it's an existing (and successful) DSL that does this. But we can invent new DSLs too.

That remains an open question - but one that we're interesting in exploring next.

Great, please loop me in to those discussions, I'd love to be part of it. I'd also like to point out that CSS-like has some prior art. Of course it doesn't have nearly as much as templating, so no idea is fully baked. But it should have time to bake more before templating is chosen which, imo, would be a major mistake.

Some links:

  • Cascading Attribute Sheets by Tab Atkins.
  • Corset a library by me, which implements some of the CSS-like ideas I've been discussing here.
  • XSLT I'll let the historians explain why that failed, but maybe there's something we can pull from it and bring into the modern web, that still accomplishes the "binding from a distance" desire?

I want to be clear that our focus and priority has been on figuring out the technical feasibility of this space. Is it possible for us to design an API that has reasonable performance and replaces the existing JavaScript code that we have in frameworks for rendering and updating rendered content? That's the question we've been building benchmarks for and discussing in depth with browser and v8 engineers. Because without answering that question, any discussion of API shape could be wasted time if we don't properly know what trade-offs from a performance and feasibility perspective we're up against.

I would suggest adding "will non-JS frameworks adopt this?" as a question to answer. Key word being will they, not can they. You can talk yourself into something being possible more easily than you can explain why they will want to do it; will requires putting yourself in their shoes and thinking about their priorities.

@bahrus
Copy link

bahrus commented Nov 10, 2023

@matthewp,

Things like loops etc are easy; you get those for free from CSS, since all selectors are "each" in CSS already.

Hmm, I'm starting to wonder if you are proposing something more radical than I thought, meaning I may have to withdraw my lukewarm endorsement, not because you are wrong, but simply because I didn't fully grasp where you were going with this, and need to ponder it more carefully.

What I was endorsing was just a lightweight way of mapping, from a distance, elements to "behavior", where those behaviors were still either custom or built-in JavaScript manipulation of the DOM (via DOM parts). Still within the confines that we want to clone templates for repeated content, achieve performance matching if not better than the horse race that's been going for years between different implementations of libraries that support for-each, that I never thought of as "easy" (though I never tried to compete in that horse race, so I have no idea how easy or hard it is). And then there's things like passing objects / functions to components inside the repeating content. This is all doable via css alone today?

Without studying your code (do you have a white paper that goes into all the details?), I'm starting to wonder if you are suggesting we start over -- forget templates, forget beefing up the DOM API, let's instead beef up CSS so it can do everything JavaScript can do, but declaratively? Something like that?

I do think that:

  1. knowing when a selector changes and
  2. the algorithm that determines which rule should apply at a given moment in time.

something along these lines but more powerful, sounds useful for a variety of purposes, including, for example, a userland implementation of custom enhancements, but I'm not seeing why requesting that should preclude efforts to continue to provide better support for templates?

@matthewp
Copy link
Author

matthewp commented Nov 10, 2023

@bahrus

Hmm, I'm starting to wonder if you are proposing something more radical than I thought, meaning I may have to withdraw my lukewarm endorsement, not because you are wrong, but simply because I didn't fully grasp where you were going with this, and need to ponder it more carefully.

I'm sorry to hear that, I didn't want to present a counter-proposal because I'm always afraid that it becomes a binary (a) or (b) choice and I don't believe in that. I only presented this CSS-like idea because @EisenbergEffect asked for pseudo-code to understand what I meant.

I think CSS-like is an interesting approach that has some historical background, but I'm equally open to any other proposal so long as it:

  1. Decouples binding from HTML creation.
  2. Does not favor any particular backend.

Without studying your code (do you have a white paper that goes into all the details?), I'm starting to wonder if you are suggesting we start over -- forget templates, forget beefing up the DOM API, let's instead beef up CSS so it can do everything JavaScript can do, but declaratively? Something like that?

No whitepaper, sorry.

That is one interesting approach that I think is worth investigating more, yes. Note that <template> is still very useful in this approach, but template as it exists today, without any magic symbols or interpolation. It's useful as a way to clone a chunk of HTML that you think manipulate via a CSS-like DSL.

something along these lines but more powerful, sounds useful for a variety of purposes, including, for example, a userland implementation of custom enhancements, but I'm not seeing why requesting that should preclude efforts to continue to provide better support for templates?

Because it's a competing idea, and in my history observing the platform I've never seen 2 competing ideas being worked on at the same time. If we continue down the template path, any other idea is going to left in the back burner for a very long time, and if templates are even moderately successful, will never be given a chance at all. So I see this as an inflection point in which it's important to fully analyze all possibilities before moving forward.

@tbondwilkinson
Copy link
Contributor

tbondwilkinson commented Nov 10, 2023

I would suggest adding "will non-JS frameworks adopt this?" as a question to answer. Key word being will they, not can they. You can talk yourself into something being possible more easily than you can explain why they will want to do it; will requires putting yourself in their shoes and thinking about their priorities.

How do non-JS frameworks handle interactivity - there's still some JS that does that, or am I missing the point?

Would you call corset a JS or non-JS framework?

@bahrus
Copy link

bahrus commented Nov 10, 2023

@matthewp

I would suggest adding "will non-JS frameworks adopt this?" as a question to answer. Key word being will they, not can they. You can talk yourself into something being possible more easily than you can explain why they will want to do it; will requires putting yourself in their shoes and thinking about their priorities.

I think I hear what you are saying to some degree, based on personal experience. However, I see rays of light that integrating non-JS server -side technologies with JS client side inline binding templates would benefit from the template binding and/or parts. For example, wordpress seems to be adopting "islands of interactivity" (using preact I think) while still utilizing PHP, in a "non-compromising way" for lack of a better term.

Note that template is still very useful in this approach, but template as it exists today, without any magic symbols or interpolation. It's useful as a way to clone a chunk of HTML that you think manipulate via a CSS-like DSL.

Okay, yes, perhaps we aren't totally apart then. I can vouch that the basic premise has some validity (from my perspective) -- from my experience, css-like dsl, combined with templates (in a very light way, which I only evaluate when dependent host props change, which is fairly easy to implement in userland) combined with custom enhancements / custom attributes like wordpress is looking at, that also can be attached based on css-like dsl, is quite powerful, and I think quite compatible with all backend technologies. I do think you are onto something, but I guess it's a matter of degree that separates us.

I also think language neutral binding syntax can work with asp.net, at least.

@bahrus
Copy link

bahrus commented Nov 11, 2023

Another potential separate thread out of this conversation, which I have to believe has probably been considered before somewhere:

What if we need to set a property / attribute for hundreds, or thousands of (custom) elements, and they are all the same, during SSR, or even after? One example I could see that being useful is for intl.* attributes, should the platform add a tag for numbers (and beef up the time tag, etc). I think it is safe to say that this violates a wall of division for CSS, as it could invoke unsafe code, but that does seem like a strong use case for what is emerging as a positive "yes, and" use case for binding from a distance, in some variant of css.

I don't see that it is "easier" from the point of view of integration with asp.net.core, php, etc, just cleaner and more performant.

@bahrus
Copy link

bahrus commented Nov 11, 2023

This is how I plan to implement the idea above in userland:

For static settings:

<html>
    <head>
        <script id=my-settings be-parsed type=application/json>
            {
                "input": {
                    "readOnly": true
                }
            }
        </script>
    </head>
<body>
        ...
        <div be-set="Apply settings from #my-settings.">
            <input>
        </div>
</body>

For dynamic settings that can be affected by the host:

<html>
    <head>
        <script id=my-settings be-parsed type=application/json>
            {
                "input": {
                    "readOnly": "isHappy"
                }
            }
        </script>
    </head>
<body>
    ...
        <mood-stone is-happy>
            #shadow
            <div be-set="Apply settings from #my-settings with model coming from host.">
                <input>
            </div>
        </mood-stone>
</body>
</html>

Uses DTR syntax, which also supports things like interpolation for hyperlinks. That syntax would benefit from DOM parts, so full steam ahead! Would also benefit from support for custom enhancements, w3c willing.

@matthewp
Copy link
Author

@tbondwilkinson

How do non-JS frameworks handle interactivity - there's still some JS that does that, or am I missing the point?

Let me clarify something that I think I haven't articulated well in this thread. My opposition to the current proposal is this:

  1. The templating proposal is helpful for those following an "isomorphic" architecture. (particularly if we include the parseparts part).
  2. Isomorphic architecture is really only possible in JS backends.
  3. Therefore, this proposal is only helpful to a subset of applications.
  4. Furthermore, this proposal is big and will take a long time and a lot of resources to see through. It will be seen as "the way" going forward and make it more difficult for alternatives to ever happen.

My counter-proposal is not attempting to solve the problem of "isomorphic" architecture. It is instead looking for another way to achieve the same underlying goals that we all want; a way to do declarative DOM updates, and it is trying to do so in a way that is decoupled from the backend.

@tbondwilkinson
Copy link
Contributor

What in particular about the proposal makes it difficult for non-JS backends to adopt? Why is it hard to generate HTML with parseparts attributes and {{}} markers in non-JS backends?

As a fun aside, isomorphic architecture is also possible in non-JS backends. One of the major frameworks for Google, Wiz, uses a templating system that produces Java code that renders the same as the produced JavaScript code, https://github.com/google/closure-templates.

But I still think even if there isn't a shared concept of template between the client and the server, this proposal could still be useful. I agree though, it would be much easier if this proposal included data bindings as a means to update DOM, rather than just providing DOM to JavaScript code. But, we have not yet proposed that alternative because exactly to your point it would make the proposal too costly to experiment with - the code that we are trying to replace would be far faster than code that used the browser to update DOM by passing in data represented in JavaScript or CSS, we believe based on benchmarks thus far. We're working to improve the data story here by improving JS bindings and passing data between JS and C++, but it's far more costly to pass a JS data object to C++ that it is to pass strings to C++.

@iteriani
Copy link

For what it's worth, most of our SSR is actually done using Java, not JS. So we will likely have to tackle this problem as well. The DOM part API is largely aimed to be flexible enough to handle all the dynamic ways existing frameworks operate on DOM nodes (ie Angular directives, signals, etc), so I can see how these features aren't as useful to a direct data -> html transform.

For action at a distance (which is a great idea!), we've messed around with an API like the following (consider the array to be interchangeable with a more structured object dsl).

const template = html(<a href={{0}}></a>);
const clone = template.clone(['/home']);
const partRoot = clone.getPartRoot();
partRoot.update(0, '/info');

This doesn't seem too different than what you are proposing.

@matthewp
Copy link
Author

matthewp commented Nov 13, 2023

@tbondwilkinson

What in particular about the proposal makes it difficult for non-JS backends to adopt? Why is it hard to generate HTML with parseparts attributes and {{}} markers in non-JS backends?

Non-JS backends do not run in the client. Generating parts is only useful if you have some code that's going to run on the client to then interpret and use those parts. Non-JS backends do not have that (with a few exceptions).

I'm aware of Wiz only from talking to Googlers, I'm sure it's able to do some incredible things but I don't think it's a good example of what is typical in non-JS frameworks. I can't really judge it anyways, since it's not open source.

@tbondwilkinson
Copy link
Contributor

What do "non-JS backends" or what I would probably term "server-only backends," do for interactivity?

If you don't send any JavaScript to the client, and have no support for client interactivity, then you have no client JavaScript to replace, and DOM parts in its initial form won't help you. If DOM parts were purely declarative, it could help you, with extensions of other APIs like invoketarget etc. And we're interesting in that in future iterations of this proposal, but it's too much to take on from the outset.

In some of your posts you've made it seem like there is a zero-sum situation, and I'm not sure I share that mindset. This API in my mind has a clear target of what code it wants to replace and what use case it wants to solve. That doesn't mean that there aren't other APIs solving other categories of problems, and I'd welcome a clearly stated user need and solution for your own requirements.

@bahrus
Copy link

bahrus commented Nov 13, 2023

Something else to consider on the plus side for adopting standard handlebar notation for the template syntax:

There exist handlebar implementations in:

  1. c#
  2. go
  3. Rust
  4. Scala
  5. php

and more I suspect.

Although it may seem far fetched, and would take years to make a dent in the current marketshare, early adopters could start leveraging these libraries in order to achieve true isomorphic support, and maybe with enough interest, the supporters behind the main server templating engines of today would take notice and begin migrating to the common syntax?

@bahrus
Copy link

bahrus commented Nov 17, 2023

I think this proposal would provide a useful primitive on top of which creating "binding from a distance" would be much easier in userland. Plus it would help resolve other important use cases. Let me know of any inaccuracies / suggestions / etc. PR's / issues welcome.

@matthewp
Copy link
Author

matthewp commented Dec 7, 2023

@tbondwilkinson I wish I shared your optimism. In my history observing web standards I've never seen 2 versions of a use-case both selected, especially when they are as big as this one is. I'm afraid that this proposal is going to cement isomorphism as the solution for declarative DOM updates, and isomorphism is a JavaScript-only concept.


The user-story is very simple: A way to declaratively update the DOM that is decoupled from the server that generated it.

@tbondwilkinson
Copy link
Contributor

I think the basic unit of this proposal, to use {{}} to mark places in the DOM that will be updated later, is not a JavaScript-only concept, nor is it reliant on any particular server architecture.

JavaScript is today the most common way of updating HTML, so to me it makes sense for that to be the first place we look when providing an API to update such marked places in the DOM. In the future, I could imagine a declarative-only syntax for updating such marked DOM parts.

The alternatives to this proposal (native HTML to mark DOM parts, JS to update them) seem less desirable. Replacing the HTML marking with some other language like XML is much more difficult, and replacing JS with CSS has been a non-starter in other proposals.

@EisenbergEffect
Copy link

EisenbergEffect commented Dec 7, 2023

The essence of this proposal is standardizing on a way to mark a location in the DOM and associate values and metadata with it. There is a fully declarative way of doing this, and there is an accompanying imperative JS API as well.

This feature should be usable with any server framework by simply generating HTML with {{}} markers. Server frameworks can provide values that render immediately without the need for JS and can also associate arbitrary metadata at those locations as well....which could be used by JS to power a front-end renderer, or it could be used for entirely different purposes, such as to power a Turbo-like or HTMX-like system.

The proposal does not provide a declarative way to update the DOM, only an imperative way AT THIS TIME. There is a desire to provide a declarative way to enable updates as well, but that was thought to be too much in the first version as it would pull in a lot of other features/work that hasn't been figured out yet and requires a lot more community discussion. Instead, the idea was to create an open syntax that could be expanded in the future to enable built-in and custom declarative syntaxes.

@matthewp
Copy link
Author

matthewp commented Dec 8, 2023

@EisenbergEffect Are there any such systems that exist today that work like this? Given that there are existing mechanisms to mark a section of HTML (like comments) and this one simply provides a better / more efficient way of doing so, you would expect to see such systems in open-source projects today. I'm not aware of such a thing.

I'm not sure I understand what you mean about there not being a declarative way, the {{}} inside of templates is declarative, at least that fits the definition I've always heard.

Also, have any backend frameworks been consulted on this proposal? Which ones?

@EisenbergEffect
Copy link

EisenbergEffect commented Dec 8, 2023

Yes, {{}} is declarative, but it's only a way of marking parts of the DOM, not controlling updates. Comments can only mark node locations, but can't mark fragments of an attribute value, like this mechanism can. This would be sort of like formalizing the comment technique that many libraries have used for years, but enhancing it to mark locations that can't be marked by a comment. It's not a way to declaratively update though. There's no binding language that handles updates. Just a syntax for encoding locations with metadata.

I'm not sure the breadth of outreach regarding backend frameworks. I've gotten a lot of feedback from front-end libraries, just via other conversations. Someone from Google or Apple might have more information about broader outreach, since they were the ones proposing this.

@iteriani
Copy link

iteriani commented Dec 8, 2023

Today you either have a compiler that directly outputs calls to .firstChild/nextSibling to get to a marker (Solid) or a DOM walk after creation to reach comments (Lit). This produces the parts during DOM creation.

@matthewp
Copy link
Author

matthewp commented Dec 8, 2023

In that case I suggest we talk to some backend framework engineers before proceeding to see if this is something they would be able to use. It's one thing to speculate on what is "possible", but it's different to know what will actually be useful to people. Only if you ask them.

@keithamus
Copy link

keithamus commented Dec 10, 2023

The proposal as is is imminently useful for its purpose of marking areas for DOM updates. The only motivation for server templates to leverage this is to co-operate with the client for dynamic updates.

At current there is an open question of what defaults will look like, which as it stands is not part of the initial iteration. I anticipate defaults will provide the opportunity for server template languages to converge on the DOM parts syntax as an output format, and maybe as an authoring format. During the 2023 Spring F2F we discussed the default syntax, some ideas were to use something like {{someExpr;default value}}. The default value would be initially rendered, but the part would remain exposed as the expression (so someExpr in the example).

With defaults template languages could use server generated values as the default while marking the part as an area for dynamic updates. Existing template languages could expose each area of dynamic content using existing syntax or new syntax. As an example an erb-like server template language might take:

<div><%= locals.username %></div>

and turn it into:

<div>{{ username ; "keithamus" }}</div>

On the initial parse the default is displayed, but upon dynamic updates the client can pull out the username expression to supply new values.

@iteriani
Copy link

@matthewp do you have any recommendations on backend frameworks to interview? I'd be happy to reach out

@matthewp
Copy link
Author

matthewp commented Dec 11, 2023

@keithamus How do those dynamic updates occur, though? That's the point of contention here. For JS based frameworks this question is answered; you use the same library to do the updates as you use for the HTML rendering. For non-JS frameworks there is no answer, and I would say cannot be answered, because making this a feature of HTML means that you have to use the same tech on server and client (or duplicate work, which no one will do).


@iteriani Thanks! Happy to provide a few suggestions, will collect a list for you.

@hawkticehurst
Copy link

hawkticehurst commented Dec 31, 2023

How do those dynamic updates occur, though? That's the point of contention here. For JS based frameworks this question is answered; you use the same library to do the updates as you use for the HTML rendering. For non-JS frameworks there is no answer, and I would say cannot be answered, because making this a feature of HTML means that you have to use the same tech on server and client (or duplicate work, which no one will do).

Was casually reading through this thread and got to the end and I really like this last question you posed @matthewp –– made a lot of things click for me.

With that said, I'm genuinely curious if I've misunderstood something: I thought there is an answer for a lot (if not all???) of these non-JS frameworks, and the answer is the same as JS frameworks –– you also just use the same library to do the updates because under the hood all non-JS frameworks do have to use some amount of JavaScript at the end of the day.

Based on my understanding of the frameworks you've mentioned –– especially the ones that use a strategy of "RPC + DOM diffing" such as Phoenix LiveView, Laravel Livewire, and Ruby Hotwire –– the vast majority of "work" in these frameworks does indeed happen on the server, but once newly generated HTML is sent back to the client there is always some amount of runtime JavaScript present to mutate the DOM so the new changes are replaced with the old changes.

I've always understood these frameworks to effectively be a tool that abstracts away the need for developers to directly write/handle dynamic updates in JavaScript and instead author dynamic websites in {insert flavor of backend}, but that doesn't mean JavaScript is somehow removed from the equation –– it's just hidden from the framework user.

If the focus of DOM Parts (at this point) is strictly a way to mark specific DOM nodes/attributes that will be changed, couldn't these frameworks also benefit from this API to make it easier to mark/access the node(s) that need to be changed/replaced and then make said change(s) using whatever method/implementation makes most sense for them?

Again I feel like I'm missing something though, so would love any clarification :)

Also here are references to the runtime JS in the above-mentioned frameworks for the curious:

@matthewp
Copy link
Author

matthewp commented Feb 22, 2024

Here's an article from someone who came up with a similar CSS idea as me, cc @tbondwilkinson. The fact that so many people are independently coming up with similar ideas here shows that the idea has some legs and should be explored.

https://knowler.dev/blog/declarative-custom-elements-should-take-inspiration-from-css


I'll reiterate, coupling HTML and DOM updates would be a mistake. Imagine if CSS had not happened and <font> and <center> were how styling worked. The DOM parts proposal is a repeat of that. Decoupling is the answer. CSS-like is one possible, but not the only solution.

@EisenbergEffect
Copy link

EisenbergEffect commented Feb 22, 2024

I think there are some interesting ideas in there. I particularly like this idea, even independent of declarative elements:

@host attribute(to: location.path) { 
  ...
}

I don't know that the article makes a strong enough case for creating an entirely new declarative language though, and one only for DCEs. That seems like an even bigger ask than handling this through HTML. I also don't see why an equivalent HTML wouldn't be just as good. For example, something like this:

<element id="NavLink">
  <attr name="to" prop></attr>
  <state name="current">{{this.to === location.path}}</state>

  <style>
    a[aria-current="page"] {
      text-decoration: none;
      color: inherit;
    }
  </style>

  <view shadowrootmode="open">
    <a part="link" href={{this.to}} aria-current="{{this.to === location.path ? 'page' : null}}">
      <slot></slot>
    </a>
  </view>
</element>

Regarding the article's DCE idea, I'm not sure how more complex scenarios would work. How is conditional rendering and list rendering handled? How do we handle rendering to the Light DOM instead of the Shadow DOM? How do we handle form association? etc. How does registration work? How does that relate to HTML Modules? For me, there are a lot of questions about the idea. I'd need to see those things addressed to be convinced of this approach. Personally, I'm open to being convinced, I just need more of the idea expanded to support a broader set of scenarios.

@bahrus
Copy link

bahrus commented Feb 22, 2024

@matthewp, I was hoping to come back with a triumphant "first came the style attribute, then came the class attribute", but it appears my memory doesn't match up with what happened, and they were both released within the same year (at least). That's how I've always looked at this question. We need the style property defined locally on the element, before we can even talk about applying that style from a distance. When I think about binding, I tend to think in terms of where more of the keyboard typing is involved, which is more like attributes. Libraries like Vue and Angular and Auralia actually stick to attributes even with for loops, the exception being when the stuff inside the for loop can't be nested inside a parent tag.

I suppose it is possible to look at a non attribute based "for-each" block surrounding a fragment of html tags as the equivalent of the font tag, only in the sense that, unlike the style and class attributes, the font tag does wrap a bunch of stuff inside. But I think the argument against the font tag was more a desire to keep things simple, and the font tag's purpose seemed to be easier to manage with inline styles (mostly (or maybe not?) applied programmatically via the property rather than attribute) and css.

But one could argue that many design libraries are in fact the equivalent of a font tag. "Use this tag and you get this look and feel with all the stuff inside". I'm perfectly okay with that, because it seems to solve a difficult problem effectively.

On the server side, few if any technologies take the approach you (and half of me) are advocating, and I've not seen a whole lot of concern raised about tightly coupling binding syntax with the outputted HTML.

Yes, you could argue that the reason they haven't, is that building the complex infrastructure needed to be able to do the kind of css matching that the browser supports would greatly increase the costs.

But you raised the issue of isomorphism earlier. How would there be any chance of isomorphism with the 100% css like approach if no server technology (I'm sure there are some very small exceptions) follow the same approach?

What the current approach on the table is basically saying to the server is "say, you know that binding syntax you are using to bind your objects to the html? Would you mind sharing some of that information with me?" Seems kind of isomorphic, doesn't it?

@matthewp
Copy link
Author

Regarding the article's DCE idea, I'm not sure how more complex scenarios would work. How is conditional rendering and list rendering handled? How do we handle rendering to the Light DOM instead of the Shadow DOM?

@EisenbergEffect I'm not the article author (but a think of a similar ideas). CSS has conditionals naturally built-in, through selectors. A selector matching or not matching is an if. As for lists, here's one approach (i think this is what you're asking about).

@sashafirsov
Copy link

@EisenbergEffect ,

How is conditional rendering and list rendering handled?

This is not relevant to the topic of this issue. But there are several answers to it.

  • via css tied to one of attributes on container. can be DCE parameters as attributes
  • via slots presented in template and their default vs payload.
  • via condition in part evaulation { someFlag ?? 'example value'}
  • via rendering instructions <xsl:if test="{someFlag='abc'}"> example value </xsl:if>

As of now I do not see a conflict between any of those approaches. All are working in custom-element DCE POC.

@matthewp
Copy link
Author

@bahrus

On the server side, few if any technologies take the approach you (and half of me) are advocating, and I've not seen a whole lot of concern raised about tightly coupling binding syntax with the outputted HTML.

Yes, you could argue that the reason they haven't, is that building the complex infrastructure needed to be able to do the kind of css matching that the browser supports would greatly increase the costs.

Yeah that's why it's not mainstream. There have been quite a lot of attempts at decoupling HTML and DOM manipulation, XSLT the most prominent example. The recent interest in CSS makes sense as somewhat of a successor to that, given CSS becoming a more powerful and attractive language in recent years and XML becoming less so (to many, at least).

But you raised the issue of isomorphism earlier. How would there be any chance of isomorphism with the 100% css like approach if no server technology (I'm sure there are some very small exceptions) follow the same approach?

There's some examples of this upthread. You do the binding in the CSS-like language. You don't do on the server at all.

What the current approach on the table is basically saying to the server is "say, you know that binding syntax you are using to bind your objects to the html? Would you mind sharing some of that information with me?" Seems kind of isomorphic, doesn't it?

No, because if your server language is Python then you write the same code twice. Once to generate initial HTML in Python. A second time to update said DOM, this time in JavaScript. Since almost no one has the bandwidth to do duplicate work, almost no one does. Thus JavaScript taking over as a server-side language, because it has the advantage of not needing to duplicate work.

Which is the whole reason for this thread existing. To convince the powers that be that server-side agnosticism is important, and worth preserving.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

10 participants