Re: [whatwg/dom] Proposal: a DocumentFragment whose nodes do not get removed once inserted (#736)

robbiespeed left a comment (whatwg/dom#736)

> How do you suppose we do server side rendering without it?

Any number of ways, it's been done many times in user space for frameworks to support hydration. If you want something like parts you could render this on the server:
```html
<button id="mybutton" class="default" data-part-attrs="class,disabled" data-part-nodes="0,2">
  <span>Default text</span>
  <!-- Part-Start -->Other default text<!-- Part-End -->
</button>
```

Then to get the parts on the client:
```js
const b = window.mybutton;
const [classAttr, disabledAttr] = b.dataset['part-attrs'].split(",").map((key) => b.getAttributeNode(key));
const bNodes = b.childNodes;
const [spanNode, textNode] = b.dataset['part-nodes'].split(",").map((i) => bNodes[i]);
span.textContent = "Something different";
```
You could add a couple helper functions if you wanted to avoid having to split and map manually.

> Hm... are you imaging that during hydration we'd move the nodes from the regular nodes to this NodeGroup object somehow? It's unclear to me what kind of use of comments and data attributes will address server-side rendering use cases.

No moving, I'm suggesting that the NodeGroup or Fragment is a pointer to nodes, so you construct that pointer using comment nodes as the separator. This is very similar to how FWs do hydration of fragments currently.

```html
<div data-fragments="1,5 7,11">
 Static Top
 <!-- Fragment-Start -->
 <span>A</span>
 <span>B</span>
 <span>C</span>
 <!-- Fragment-End -->
 Static Middle
 <!-- Fragment-Start -->
 <span>D</span>
 <span>E</span>
 <span>F</span>
 <!-- Fragment-End -->
 Static Bottom
</div>
```
```js
const nodes = el.childNodes;
const groups = el.dataset.fragments.split(" ")
  .map((startEnd) =>
    // createNodeGroup takes start and end nodes similar to Range
    // does not move the nodes into the group but the group can reference all nodes in the range 
    document.createNodeGroup(...startEnd.split(",").map((i) => nodes[i]))
  );
```
The difference between a group and range would be the interface, group looks like a node and can be inserted/moved like one (moves all nodes within the group), Unlike ranges which maintain there references relative to the parent node fragments maintain references relative to start and end nodes.
```js
const ranges = el.dataset.fragments.split(" ")
  .map((startEnd) => {
    const [start, end] = startEnd.split(",");
    const r = new Range();
    r.setStartBefore(nodes[start]);
    r.setEndAfter(nodes[end]);
    return r;
  });

ranges[0].toString(); // "A B C"

// Move the first group and it's content to before "Static Bottom"
el.insertBefore(groups[0], el.lastChild);

groups[0].firstChild.textContent // "A"
ranges[0].toString(); // empty
```

> That would be a major departure from the current model of DOM nodes, and it would pose major implementation challenges.

Can you speak to what those challenges would be. It doesn't seem that far of a departure to say that the group doesn't act as a parent node.

> This is why NodeGroup being a part of DOM tree is an appealing alternative. Then you can easily insert an empty fragment / group. I'm not necessarily advocating for one approach or the other but being able to handle empty group case without much complexity seems important.

What is the difference between an empty group being represented by 2 start and end comments vs new special start and end tags? The comment approach seems much more backward compat friendly and easier to polyfill for. I don't even think it would be possible to polyfill a `NodeGroup` that was part of the DOM tree, which would make adoption take longer.

-- 
Reply to this email directly or view it on GitHub:
https://github.com/whatwg/dom/issues/736#issuecomment-2759861429
You are receiving this because you are subscribed to this thread.

Message ID: <whatwg/dom/issues/736/2759861429@github.com>

Received on Friday, 28 March 2025 00:10:02 UTC