Skip to content

only run render effect for children of non-void <svelte:element> #10884

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

Closed
wants to merge 1 commit into from

Conversation

Rich-Harris
Copy link
Member

I don't know if this is a good idea or not, but I encountered it while looking at the hydrate_block_anchor function:

export function hydrate_block_anchor(node) {
if (!hydrating) return;
if (node.nodeType === 8) {
// @ts-ignore
let fragment = node.$$fragment;
if (fragment === undefined) {
fragment = get_hydration_fragment(node);
} else {
schedule_task(() => {
// @ts-expect-error clean up memory
node.$$fragment = undefined;
});
}
set_current_hydration_fragment(fragment);
} else {
const first_child = /** @type {Element | null} */ (node.firstChild);
set_current_hydration_fragment(first_child === null ? [] : [first_child]);
}
}

In all but 5 tests, anchor is a Comment. 3 of those tests relate to this...

<svelte:element this={somethingvoid}>
  <p>invalid children (because this is a void element)</p>
</svelte:element>

...and if we can avoid creating the children for these elements then there'll only be 2 tests where anchor isn't a Comment, and if we can figure out those edge cases then maybe we can simplify that function by enforcing that its argument is always a Comment. Fewer if branches makes everything more understandable, and every microsecond counts during hydration.

It turns out we can determine which elements are void by checking to see if element.outerHTML contains a solidus (/). Admittedly, this trades work in one place for work in another. Just putting it up for discussion for now.

Copy link

changeset-bot bot commented Mar 22, 2024

⚠️ No Changeset found

Latest commit: 0a6b14e

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

* @returns {boolean}
*/
function is_void(element) {
if (!void_elements.has(element.nodeName)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hoist nodeName into a var

@trueadm
Copy link
Contributor

trueadm commented Mar 23, 2024

Can we be certain about the outerHTML trick? Are there any false positives that might come about from this at all? This SO recommends >< https://stackoverflow.com/questions/27786815/how-can-i-test-if-an-element-is-self-enclosed-in-javascript

@Rich-Harris
Copy link
Member Author

Rich-Harris commented Mar 23, 2024

I think >< and / are equivalent. I can't imagine why there'd be any false positives.

Either way, I worked around this in #10891 by skipping the child render function if child_anchor is undefined, which would only be the case if hydrating a void dynamic element. It means that child content of void elements would still be 'rendered' when not hydrating, but that probably doesn't matter.

@Rich-Harris
Copy link
Member Author

I'm going to close this since there's a sensible workaround and it's a sufficiently rare case to not worry about

@Conduitry Conduitry deleted the skip-void-children branch August 15, 2024 10:19
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

Successfully merging this pull request may close these issues.

2 participants