Skip to content
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

Empty comment in HTML breaks hydration #14323

Open
Azarattum opened this issue Nov 16, 2024 · 8 comments
Open

Empty comment in HTML breaks hydration #14323

Azarattum opened this issue Nov 16, 2024 · 8 comments
Assignees

Comments

@Azarattum
Copy link
Contributor

Azarattum commented Nov 16, 2024

Describe the bug

The Problem

I'm trying to implement a manual hydration for some parts of my application. Which means I need to render components to a string and pass them to @html to avoid Svelte hydrating this parts of my application automatically. E.g.

<script>
  import { render } from "svelte/server";
</script>
 
<!-- svelte-ignore hydration_html_changed -->
{@html import.meta.env.SSR ? render(someComponent).body : " "}

The problem is that render(someComponent).body contains empty comments (<!---->) for its future hydration. And you get a mismatch because these comments are misinterpreted as the end of @html block.

Possible Solution

Make sure that @html block are closed with a "hash comment" and ignore every other comment. This change should be as simple as replacing (next).data !== '' with (next).data !== hash here. If this is an acceptable solution, I can make a PR.

Use Case

My use case might seem weird to you. I've posted more details on discord. We could discuss it there if needed.

Reproduction

Minimal reproduction:

{@html "<!---->"}

Observe:

hydration_mismatch:
  Hydration failed because the initial UI does not match what was rendered on the server

Logs

No response

System Info

System:
    OS: macOS 14.6.1
    CPU: (8) arm64 Apple M1
    Memory: 135.31 MB / 16.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 23.1.0 - /opt/homebrew/bin/node
    npm: 10.9.0 - /opt/homebrew/bin/npm
    pnpm: 9.4.0 - ~/Library/pnpm/pnpm
    bun: 1.1.31 - ~/.bun/bin/bun
  Browsers:
    Brave Browser: 130.1.71.123
    Safari: 17.6
  npmPackages:
    svelte: ^5.0.0 => 5.0.2

Severity

annoyance

@paoloricciuti
Copy link
Member

The hash is only added during dev to give you the runtime error in case of mismatch and will not be there in production.

But also, considering that what you are trying to achieve is purely client side why do you need this?

@Azarattum
Copy link
Contributor Author

Hmm... So, there are no hashes in prod... Could it be a good idea to make comments defining @html block different from the others anyway (even without hashes)?

While most of what I need is client-side, it still operates on DOM coming from the server (CSR-only is unacceptable in my use case). Since Svelte doesn't have partial (component level) hydration yet, using the @html and render() is the only way I've found to opt out of hydration for a piece of code. Here is a small demo of what I have achieved so far: REPL.

The ultimate goal of this is to preserve state (including DOM references and any modifications done outside of Svelte) between route navigations. E.g. imagine a tab-view where each tab is its own route with SSR, but when navigating between them on a client you keep all the state for each tab. Unfortunately, snapshot API or using layouts is too limiting. This is my I'm making this.

@Azarattum
Copy link
Contributor Author

The importance of keep-alive like behaviour has already been discussed here. This solution would also be a possible workaround for #12895 - REPL, since it uses global IDs for component caching.

@Azarattum
Copy link
Contributor Author

I've made a full-stack tab-view demo. Note the content!.body.replaceAll("<!---->", "<!----->") in KeepAlive.svelte. The replace is a workaround for the problem described in this issue. I'm not sure how safe it is to do that. Is it OK for hydration to accept any comment or should it always have data = ""? From my testing this workaround kind of works so far. I'm not sure, though. Maybe I'm missing something.

@trueadm
Copy link
Contributor

trueadm commented Nov 17, 2024

I wonder if the correct solution is that we have a better API for these cases, see #14337.

@Azarattum
Copy link
Contributor Author

#14337 would solve this issue.

Unfortunately, this issue is just a part of a problem for my use-case. There are some other problems with my current implementation. For example, any transitions inside KeepAlive wound't work (since components aren't technically mounted). Ideally such the functionality should be provided on a framework level instead of being hacked on top in userland. #6040 was closed waiting for an RFC. I guess I can draft one if you think this is the right direction. Otherwise if we want to keep this in userland, we need more advanced APIs for these use cases (e.g. see #6942 (comment)). I think @Rich-Harris mentioned that he has ideas for a new transition API. I'm curious if they could align with our goals here.

@Leonidaz
Copy link

I wonder if the correct solution is that we have a better API for these cases, see #14337.

I don't think #14337 solves this use case because of the intention to hydrate the ssr-d output (to avoid svelte-controlled unmount). #14337 would help with purely server components with no interactivity or just static email markup.

This issue is purely on the hydration mismatch warning (supposedly in dev only) when used in rendering components via the server-side render() api function, placing the output in {@html } and then calling hydrate() on the component load on the client-side.

@trueadm
Copy link
Contributor

trueadm commented Nov 19, 2024

After speaking to @Rich-Harris about this, we feel the correct fix for this is to make it so the @html block can handle comments inside the content without hydration breaking. This would involve adding starting and ending comments to the content for the raw block.

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

No branches or pull requests

5 participants