Skip to content

{@html ...} tag is populated too late #7341

Open
@Rich-Harris

Description

@Rich-Harris

Describe the bug

Bear with me, this is a bit of an edge case.

If you have code like this...

<script>
	let h = 0;

	const html = '<div style="height: 50vh"></div><div style="height: 100vh; background: salmon"><h3 id="foo">this should be at the top of the page</h3></div>';
</script>

<div bind:clientHeight={h} /><main>{@html html}</main>

it will compile with hydratable: true to this:

		/* omitted */
		l(nodes) {
			div = claim_element(nodes, "DIV", {});
			children(div).forEach(detach);
			main = claim_element(nodes, "MAIN", {});
			var main_nodes = children(main);
			main_nodes.forEach(detach);
			this.h();
		},
		h() {
			add_render_callback(() => /*div_elementresize_handler*/ ctx[1].call(div));
		},
		m(target, anchor) {
			insert_hydration(target, div, anchor);
			div_resize_listener = add_resize_listener(div, /*div_elementresize_handler*/ ctx[1].bind(div));
			insert_hydration(target, main, anchor);
			main.innerHTML = html;
		},
		/* omitted */

Between main_nodes.forEach(detach) and main.innerHTML = html, the addition of the resize listener causes a reflow that, long story short, results in you losing your scroll position if you were previously scrolled to #foo and there's not much content on the page other than the contents of {@html ...}. This is currently visible on the SvelteKit docs: sveltejs/kit#4216. (Only on Chrome, not Firefox.)

Removing the bind:clientHeight (or placing it below the {@html ...}) prevents the bug, as would using a ResizeObserver instead of the resize listener hack. But the biggest mystery is why we're waiting until the mount phase (m) to do innerHTML = html instead of the claim phase (l).

(Aside: it would be nice if there was a way to say 'you don't need to replace me, I promise my contents won't have changed since SSR' — {@html:leavemealone post.html} or whatever.)

Reproduction

Open this StackBlitz repro and go to the standalone version: https://sveltejs-kit-template-default-pm2sdq--3000.local.webcontainer.io/

Logs

No response

System Info

System:
    OS: macOS 12.0.1
    CPU: (10) arm64 Apple M1 Max
    Memory: 90.30 MB / 32.00 GB
    Shell: 5.8 - /bin/zsh
  Binaries:
    Node: 16.13.1 - ~/.nvm/versions/node/v16.13.1/bin/node
    Yarn: 1.22.17 - ~/.nvm/versions/node/v16.13.1/bin/yarn
    npm: 8.1.2 - ~/.nvm/versions/node/v16.13.1/bin/npm
  Browsers:
    Chrome: 98.0.4758.109
    Firefox: 97.0.1
    Safari: 15.1
  npmPackages:
    svelte: ^3.43.0 => 3.44.2

Severity

annoyance

Metadata

Metadata

Assignees

No one assigned

    Labels

    compilerChanges relating to the compiler

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions