Skip to content

Incorrect target of text effect is chosen when hydrating a component that renders an empty string during SSR #10486

@jarrodldavis

Description

@jarrodldavis

Describe the bug

If I have a component like this:

<script>
    let text = $state('');

    function update_text() {
        text = 'updated';
    }
</script>

<button type="button" on:click={update_text}>Update Text</button>

<div>{text}<br /></div>

that is rendered during SSR, clicking on the button after loading the page doesn't work. It appears that hydrating any component that renders an empty string next to one other sibling element incorrectly selects that sibling element as the target of a text_effect since there's no text node to select.

Curiously, adding a bit of static text before the expression works:

<script>
    let text = $state('');

    function update_text() {
        text = 'updated';
    }
</script>

<button type="button" on:click={update_text}>Update Text</button>

<div>Text:{text}<br /></div>

Reproduction

I've created a reproduction SvelteKit app that demonstrates the issue in a single <div> element as well as closer to how I initially found the issue, using an {#each} block over an array of lines of text.

In the latter reproduction, I also log out the child nodes of the first and third lines to demonstrate the missing text node. In the compiled CSR output, the issue is present here:

	$.each_indexed(
		node,
		() => lines,
		73,
		($$anchor, line, $$index) => {
			/* Init */
			var div = $.open($$anchor, true, each_block);
			var text = $.child(div);
			var br = $.sibling($.child(div));

			/* Update */
			$.text_effect(text, () => $.unwrap(line));
			$.close($$anchor, div);
		},
		null
	);

Since $.open handles hydration, that selects the SSR-rendered div that only has a <br> child, which $.child then selects as the (incorrect) target of $.text_effect. When line is updated, $.text_effect attempts to set the nodeValue on the <br> instead of a text node.

I was able to track down when this was introduced, and pushed up a branch where these components seem to work as expected on [email protected]. This tracks since 5.0.0-next.43 specifically included changes for empty text hydration issues.

Logs

No response

System Info

System:
    OS: Linux 6.2 Ubuntu 20.04.6 LTS (Focal Fossa)
    CPU: (2) x64 AMD EPYC 7763 64-Core Processor
    Memory: 5.20 GB / 7.74 GB
    Container: Yes
    Shell: 5.0.17 - /bin/bash
  Binaries:
    Node: 20.11.0 - ~/nvm/current/bin/node
    Yarn: 1.22.19 - /usr/bin/yarn
    npm: 10.2.4 - ~/nvm/current/bin/npm
    pnpm: 8.15.1 - ~/nvm/current/bin/pnpm
  npmPackages:
    svelte: 5.0.0-next.54 => 5.0.0-next.54

Severity

annoyance

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions