-
Notifications
You must be signed in to change notification settings - Fork 77
Description
Based on a discussion with Copilot, I’ve decided to allow the renderer adapter API to produce Text()
nodes, to give each string in the element tree its own personal Text()
node, and to remove logic which concatenates adjacent strings before passing them to the internal renderer. Creating, tracking and retaining text nodes in direct correspondence with the strings in the element tree will likely improve performance and simplicity.
The rationale:
-
Performance: Retaining split text nodes simplifies update logic during reconciliation and hydration, potentially leading to performance gains.
-
Convenience: If we track text nodes, we can return them as the rendered value of a component. While you cannot access rendered strings with refs, they will now be surfaced to lifecycle APIs.
function Component() { this.schedule((node) => { // node is now a TextNode rather than a string // This enables direct manipulation or observation of the DOM node, // such as setting properties, reading textContent, or using DOM APIs. // For example: node.textContent = "Updated text"; // or logging: console.log(node instanceof Text); // true }); return "Hello world"; }
This issue will likely also include the addition of a new special
<Text>
element tag, similar to<Raw>
to allow the creation of DOMText()
nodes.yield ( <Text value="Hello world" /> );
-
Maintainability: Attempts to deduplicate or merge text nodes across boundaries (e.g., when a component or fragment returns a string as its first child) introduce algorithmic complexity, break component encapsulation, and add fragility to updates and hydration. The current text concatenation logic does not handle components or fragments which start or end with text and have text siblings, so it was never going to concatenate all logically adjacent strings.
-
Security: While not concatenating strings before passing them to the renderer is a potential security concern, HTML is escaped on a per character basis, so concatenation does not provide extra protection against XSS or injection. On the DOM side, Text nodes, whether split or merged, are safe as long as escaping is done correctly.
-
Hydration: Hydration logic can be adapted to handle split text nodes by chopping or merging as needed. Strict merging is not necessary.
TODO:
- Refactor text node handling so that adjacent text nodes are not concatenated as siblings.
- Update hydration and reconciliation methods in RenderAdapter to consistently handle split text nodes and test for edge cases.
- Remove legacy code that handled merging/concatenating text nodes.