Skip to content

SSR hydration bug with @html and localStorage #9057

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
formula349 opened this issue Jul 29, 2023 · 9 comments
Closed

SSR hydration bug with @html and localStorage #9057

formula349 opened this issue Jul 29, 2023 · 9 comments

Comments

@formula349
Copy link

Describe the bug

I have a custom Table.svelte component that renders a table given an array of column definitions and an array of row data objects. This Table component supports sorting by clicking on the headers of the column and it saves that sort preference in localStorage.

When this component hydrates on the client you will see the table update to sort properly based on the last saved settings in localStorage. This is expected and works fine unless:

If any of the cells render using {@html cellValue}, the client-side sort will not update that column on initial render. This will leave some columns sorted properly and others not sorted and now associated with the wrong row.

It took a while to isolate this to the @html tag. I've tried all of the tricks for reactivity like [...data] array copying, {#key} and indexes on {#each} blocks. The only thing that fixed the sorting problem is to not use @html.

I'm working around this now by exposing a slot in my table component where I don't need to use @html, but this is definitely a problem for situations that require rendering HTML from a string.

Reproduction

https://www.sveltelab.dev/oksrlmbygtswbzd

  1. Load the sveltelab project and click on the Name column to sort by name. You should see the sorting working properly.
    image

  2. Click the UI view refresh to SSR and hydrate the page and you'll see the name sort kick in, but the names don't match the emails anymore.
    image

Logs

No response

System Info

New sveltelab.dev running on Chrome browser.

  System:
    OS: Linux 5.0 undefined
    CPU: (8) x64 Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
    Memory: 0 Bytes / 0 Bytes
    Shell: 1.0 - /bin/jsh
  Binaries:
    Node: 16.20.0 - /usr/local/bin/node
    Yarn: 1.22.19 - /usr/local/bin/yarn
    npm: 9.4.2 - /usr/local/bin/npm
    pnpm: 8.6.3 - /usr/local/bin/pnpm
  npmPackages:
    @sveltejs/adapter-auto: ^2.0.0 => 2.1.0 
    @sveltejs/kit: ^1.20.4 => 1.22.3 
    svelte: ^4.0.0 => 4.1.1 
    vite: ^4.3.6 => 4.4.7

Severity

serious, but I can work around it

Additional Information

This was confirmed by a few other users on the Svelte discord. See this thread for reference.

https://discord.com/channels/457912077277855764/1134549192174489630

@benmccann benmccann transferred this issue from sveltejs/kit Jul 29, 2023
@StagnantIce
Copy link

I try with "{#each displayData as row, i (i)}" instead {#key sortIndex} and its works, can you try?

@formula349
Copy link
Author

formula349 commented Aug 1, 2023

That did not fix the problem. When you update the code it will sort it properly, so you'd have to refresh the app to see this SSR hydration bug again.

@Crenshinibon
Copy link

Same here. I've a wordy workaround using an "action" instead of @html as described here: https://youtu.be/R_C8jLh5yIs?t=13

@Crenshinibon
Copy link

Will this be resolved any time soon or with Svelte 5 automatically?

I planned to go live this year and I'm relying on the @html heavily to translate many parts of my app.

@epavanello
Copy link

Take a look on the duplicated issue, the replication case is extremely easy to reproduce.

@robertadamsonsmith
Copy link

This issue also appears in Svelte 5. A minimal repro is:

<div>{typeof window !== 'undefined'}</div>
<div>{@html typeof window !== 'undefined'}</div>

On page load, both divs will initially be false (expected). The first div will immediately change to true after hydration (expected). The second div will remain false (unexpected).

@mdulc928
Copy link

mdulc928 commented Nov 27, 2024

Facing this same issue for while translating my website too ☹️ , and am using Svelte 5.

@Conduitry
Copy link
Member

https://svelte.dev/docs/svelte/v5-migration-guide#Other-breaking-changes-img-src-and-html-hydration-mismatches-are-not-repaired

In Svelte 5, it is intended that {@html} not repair hydration mismatches because of the performance impact of doing so.

@Conduitry Conduitry closed this as not planned Won't fix, can't repro, duplicate, stale Nov 27, 2024
@mdulc928
Copy link

I'm going to comment for anyone else who happens to land on this issue.

Disclaimer: this may be a really, really bad idea in terms of how this affects what Svelte compiles. There is something seriously smelly about what I'm about to suggest, so my apologies to the wonderful Svelte maintainers (seriously, y'all, thanks for all the work) if I'm committing some grave sin.

Context: All I needed was a fast landing page with decent performance and translation.

So, @Crenshinibon what I did to solve this in Svelte 5 with this response #9057 (comment) in mind:

  • In +layout.svelte, I have added an isLoading state (might be better named, but the cognitive overhead this has costed me is enough already 😅 ).
  • Do the check and update that state variable to true as shown in the link from SSR hydration bug with @html and localStorage #9057 (comment).
  • Do not render your page until isLoading is false (I just wrapped my entire {@render children()} with that condition).

Although, it is unfortunate that this this is what we have to do, it does make sense (that's what you have to do in React, and I imagine other frameworks too?).

Some pros I discovered when I thought of this:

  1. My loading speed improved by a good margin 😄 .
  2. The users don't see the flash.
  3. Logic in the +page.svelte went back to being simple.
  4. The result was correct and deterministic.
    • Aside: Perhaps correctness and determinism should not be overlooked when optimizing for performance in development, especially when you're developing a programming language/framework which by nature should be deterministic. It might be fast, but it is still wrong. Hopefully this is constructive feedback, @Conduitry, forgive me for tagging you.

Cons:

  1. My hero image took slightly more time to render, but that was fine by my standards.

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 a pull request may close this issue.

7 participants