sveltejs / kit

web development, streamlined
https://kit.svelte.dev
MIT License
17.97k stars 1.8k forks source link

Hydration Mismatch Bug / Svelte 5 #12209

Closed eftichis0202 closed 1 month ago

eftichis0202 commented 1 month ago

Describe the bug

I have this Bug in svelte 5, without any indications on how to fix it:

<div aria-expanded="true" tabindex="-1" style="box-sizing: border-box; min-width: 0px; min-height: 0px; outline-width: 0px; flex: 0 0 auto; color: rgb(227, 227, 227); font-family: monospace; font-size: 11px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgb(65, 60, 38); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;"><span class="source-code" style="box-sizing: border-box; min-width: 0px; min-height: 0px; font-family: var(--source-code-font-family); white-space: pre-wrap; font-size: var(--source-code-font-size) !important; line-height: 1.2;"><span class="console-message-anchor" style="box-sizing: border-box; min-width: 0px; min-height: 0px; float: right; text-align: right; max-width: 100%; margin-left: 4px;"><button class="devtools-link text-button link-style" role="link" tabindex="-1" title="http://localhost:5173/:2157" style="box-sizing: border-box; min-width: 0px; min-height: 0px; font: inherit; margin: 0px; height: unset; border: none; border-radius: 2px; padding: 0px !important; color: var(--sys-color-primary); background: none; flex: 0 0 auto; white-space: nowrap; text-decoration: underline; outline-offset: 2px; outline: none; cursor: pointer; word-break: break-all;"><br class="Apple-interchange-newline">(index):2157</button> </span><span class="console-message-text" style="box-sizing: border-box; min-width: 0px; min-height: 0px; color: var(--sys-color-on-surface-yellow);"><span style="box-sizing: border-box; min-width: 0px; min-height: 0px; contain: paint; display: inline-block; max-width: 100%; font-weight: bold;">[svelte] hydration_mismatch</span><br style="box-sizing: border-box; min-width: 0px; min-height: 0px;"><span style="box-sizing: border-box; min-width: 0px; min-height: 0px; contain: paint; display: inline-block; max-width: 100%; font-weight: bold;"></span><span style="box-sizing: border-box; min-width: 0px; min-height: 0px; contain: paint; display: inline-block; max-width: 100%; font-weight: normal;">Hydration failed because the initial UI does not match what was rendered on the server</span></span></span></div><div class="" role="group" style="box-sizing: border-box; min-width: 0px; min-height: 0px; flex: 0 0 auto; color: rgb(227, 227, 227); font-family: monospace; font-size: 11px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgb(65, 60, 38); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;"><span class="monospace stack-preview-container width-constrained" style="display: inline-block; --monospace-font-size: 11px; --monospace-font-family: monospace; --source-code-font-size: 11px; --source-code-font-family: monospace; width: 1738px; box-sizing: border-box; min-width: 0px; min-height: 0px; font-family: var(--monospace-font-family); font-size: var(--monospace-font-size) !important;">
  | warn | @ | client.js?v=821c5962:2639
-- | -- | -- | --
  | hydration_mismatch | @ | chunk-NWCJ2XGV.js?v=821c5962:600
  | hydrate | @ | chunk-NWCJ2XGV.js?v=821c5962:2291
  | Svelte4Component | @ | chunk-NWCJ2XGV.js?v=821c5962:2442
  | (anonymous) | @ | chunk-NWCJ2XGV.js?v=821c5962:2419
  | initialize | @ | client.js?v=821c5962:434
  | _hydrate | @ | client.js?v=821c5962:2386
  | await in _hydrate (async) |   |  
  | start | @ | client.js?v=821c5962:293
  | (anonymous) | @ | (index):2157
  | Promise.then (async) |   |  
  | (anonymous) | @ | (index):2156
  | Show less

</span></div>

What needs to be addressed here to fix this bug?

Reproduction

I have this Bug in svelte 5, without any indications on how to fix it:

<div aria-expanded="true" tabindex="-1" style="box-sizing: border-box; min-width: 0px; min-height: 0px; outline-width: 0px; flex: 0 0 auto; color: rgb(227, 227, 227); font-family: monospace; font-size: 11px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgb(65, 60, 38); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;"><span class="source-code" style="box-sizing: border-box; min-width: 0px; min-height: 0px; font-family: var(--source-code-font-family); white-space: pre-wrap; font-size: var(--source-code-font-size) !important; line-height: 1.2;"><span class="console-message-anchor" style="box-sizing: border-box; min-width: 0px; min-height: 0px; float: right; text-align: right; max-width: 100%; margin-left: 4px;"><button class="devtools-link text-button link-style" role="link" tabindex="-1" title="http://localhost:5173/:2157" style="box-sizing: border-box; min-width: 0px; min-height: 0px; font: inherit; margin: 0px; height: unset; border: none; border-radius: 2px; padding: 0px !important; color: var(--sys-color-primary); background: none; flex: 0 0 auto; white-space: nowrap; text-decoration: underline; outline-offset: 2px; outline: none; cursor: pointer; word-break: break-all;"><br class="Apple-interchange-newline">(index):2157</button> </span><span class="console-message-text" style="box-sizing: border-box; min-width: 0px; min-height: 0px; color: var(--sys-color-on-surface-yellow);"><span style="box-sizing: border-box; min-width: 0px; min-height: 0px; contain: paint; display: inline-block; max-width: 100%; font-weight: bold;">[svelte] hydration_mismatch</span><br style="box-sizing: border-box; min-width: 0px; min-height: 0px;"><span style="box-sizing: border-box; min-width: 0px; min-height: 0px; contain: paint; display: inline-block; max-width: 100%; font-weight: bold;"></span><span style="box-sizing: border-box; min-width: 0px; min-height: 0px; contain: paint; display: inline-block; max-width: 100%; font-weight: normal;">Hydration failed because the initial UI does not match what was rendered on the server</span></span></span></div><div class="" role="group" style="box-sizing: border-box; min-width: 0px; min-height: 0px; flex: 0 0 auto; color: rgb(227, 227, 227); font-family: monospace; font-size: 11px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgb(65, 60, 38); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;"><span class="monospace stack-preview-container width-constrained" style="display: inline-block; --monospace-font-size: 11px; --monospace-font-family: monospace; --source-code-font-size: 11px; --source-code-font-family: monospace; width: 1738px; box-sizing: border-box; min-width: 0px; min-height: 0px; font-family: var(--monospace-font-family); font-size: var(--monospace-font-size) !important;">
  | warn | @ | client.js?v=821c5962:2639
-- | -- | -- | --
  | hydration_mismatch | @ | chunk-NWCJ2XGV.js?v=821c5962:600
  | hydrate | @ | chunk-NWCJ2XGV.js?v=821c5962:2291
  | Svelte4Component | @ | chunk-NWCJ2XGV.js?v=821c5962:2442
  | (anonymous) | @ | chunk-NWCJ2XGV.js?v=821c5962:2419
  | initialize | @ | client.js?v=821c5962:434
  | _hydrate | @ | client.js?v=821c5962:2386
  | await in _hydrate (async) |   |  
  | start | @ | client.js?v=821c5962:293
  | (anonymous) | @ | (index):2157
  | Promise.then (async) |   |  
  | (anonymous) | @ | (index):2156
  | Show less

</span></div>

What needs to be addressed here to fix this bug?

Logs

console log is in the description above.

Server log:

` pnpm run dev

> oux-web@0.0.1 dev /Users/eftichis0202/Avriofilms M.I.K.E Dropbox/Felix Schneider/06 Websites/03 Zuschuss Zentrale/_NEW Repos/oux-web
> vite dev

3:13:19 PM [vite-plugin-svelte] You are using Svelte 5.0.0-next.123. Svelte 5 support is experimental, breaking changes can occur in any release until this notice is removed.
work in progress:
 - svelte-inspector is disabled until dev mode implements node to code mapping

  VITE v5.2.11  ready in 3712 ms

  ➜  Local:   http://localhost:5173/
  ➜  Network: use --host to expose
  ➜  press h + enter to show help
[15:13:22.306] DEBUG (57771): Dev mode: populating platform env var`

System Info

System:
    OS: macOS 13.6.6
    CPU: (12) x64 Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
    Memory: 13.16 MB / 16.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 21.7.1 - /usr/local/bin/node
    npm: 10.5.0 - /usr/local/bin/npm
    pnpm: 9.0.4 - ~/Library/pnpm/pnpm
  Browsers:
    Chrome: 124.0.6367.158
    Safari: 17.4.1
  npmPackages:
    @sveltejs/adapter-cloudflare: ^4.4.0 => 4.4.0 
    @sveltejs/kit: ^2.5.7 => 2.5.7 
    @sveltejs/vite-plugin-svelte: ^3.1.0 => 3.1.0 
    svelte: 5.0.0-next.123 => 5.0.0-next.123 
    vite: ^5.2.11 => 5.2.11

Severity

serious, but I can work around it

Additional Information

No response

dummdidumm commented 1 month ago

Please provide a reproduction or we can't help you.

eftichis0202 commented 1 month ago

@dummdidumm How can i provide this to you?

Rich-Harris commented 1 month ago

Per the issue template,

A link to a repository, or a fork of https://node.new/sveltekit, that reproduces the issue. Reproductions must be short, self-contained and correct and must not contain files or code that aren't relevant to the issue — please do NOT just paste a link to your project. Explaining how to reproduce is generally not enough. It pushes the burden of creating a reproduction project onto a small set of volunteer maintainers and isn't scalable. If no reproduction is provided, the issue will be closed.

eftichis0202 commented 1 month ago

@Rich-Harris The problem is that i don't know what is causing this issue. The error message doens't give me any information i can work with. How would i know which part of the svelte app to share with you in the reproduction? Or do i put the entire repo in there in such a case?

dummdidumm commented 1 month ago

Try to remove parts of the app until the error no longer shows up. Then you know roughly in what area it appears. Then you can likely remove more stuff that is irrelevant. Then you can share the reproduction

eftichis0202 commented 1 month ago

Thank you, that helped narrowing it down. I found the code that causes this issue, i don't understand why this is happening though.:

<script lang="ts">
    import { ChevronRight, Phone, Mail, LucideTableCellsMerge, ChevronLeft } from 'lucide-svelte';
    import { swiperSlideOUXNews } from '../data/slides';
    import { onDestroy, onMount } from 'svelte';

    let scrollElement = $state<HTMLElement>();
    let currentSlide = $state(0);
    const totalSlides = swiperSlideOUXNews.length;

    function handleScroll() {
        if (!scrollElement) return;
        const slideWidth = scrollElement.offsetWidth;
        const newIndex = Math.round(scrollElement.scrollLeft / slideWidth);
        if (newIndex !== currentSlide) {
            currentSlide = newIndex;
        }
    }

    function nextSlide() {
        currentSlide = (currentSlide + 1) % totalSlides;
        scrollToCurrentSlide();
    }

    function prevSlide() {
        currentSlide = (currentSlide - 1 + totalSlides) % totalSlides;
        scrollToCurrentSlide();
    }

    function scrollToCurrentSlide() {
        if (!scrollElement) return;
        const slideWidth = scrollElement.offsetWidth;
        scrollElement.scrollLeft = slideWidth * currentSlide;
    }

    $inspect(currentSlide);

    onMount(() => {
        if (scrollElement) {
            scrollElement.addEventListener('scroll', handleScroll);
            scrollToCurrentSlide();
            return onDestroy(() => {
                if (scrollElement) {
                    scrollElement.removeEventListener('scroll', handleScroll);
                }
            });
        }
    });
</script>

<section class="">
    <div class="mt-20"></div>
    <div class="ml-8 md:mx-52 md:text-center">
        <div id="oux-news" class="leading-12 font-kanit text-5xl font-extrabold uppercase">
            OMEGAUX<br class="md:hidden" /> NEWS
        </div>
    </div>
    <div class="mb-8 ml-8 flex justify-start md:mx-52 md:justify-center">
        <div class="mt-6 h-1 w-1/3 bg-flamingo-500 md:w-1/12"></div>
    </div>
    <div class="relative md:mt-20">
        <div
            class=" overflow flex snap-x snap-mandatory flex-row overflow-x-scroll"
            bind:this={scrollElement}
        >
            {#each swiperSlideOUXNews as article, i}
                <div id={article.sliderID} class=" w-screen flex-shrink-0 snap-start">
                    <div
                        class="flex min-h-60 items-center bg-cover md:mx-52"
                        style="background-image: url('{article.image}');"
                    >
                        <h1 class="p-12 text-2xl md:justify-center">{@html article.title}</h1>
                    </div>
                    <div class="flex flex-row justify-between border-b border-flamingo-500 p-6 md:mx-52">
                        <div class="flex">
                            <img
                                class="h-12 w-12 rounded-full object-cover"
                                src={article.authorImage}
                                alt={article.title}
                            />
                            <div class="ml-4">
                                <h1 class="font-quattrocentoSans text-base font-bold">{article.author}</h1>
                                <h1 class="font-quattrocentoSans text-sm font-extralight">{article.date}</h1>
                            </div>
                        </div>
                        <!-- TODO Unhide and make into scheduling button? -->
                        <button class="hidden">
                            <img src="Button-Heart.svg" alt="HeartSVG" class=" h-12 w-12" />
                        </button>
                    </div>
                    <div class="border-b border-flamingo-500 bg-steel-gray-900 pb-6 md:mx-52">
                        <p class="px-8 pt-4 font-quattrocentoSans text-base">
                            {@html article.descriptionPath}
                        </p>
                        <!-- TODO Unhide and implement functionality -->
                        <img src="Button-Share.svg" alt="Share" class="mb-6 ml-8 mt-6 hidden h-10" />
                    </div>
                </div>
            {/each}
        </div>
        <button class="absolute left-0 top-24 z-50 md:left-32" onclick={prevSlide}>
            <ChevronLeft class="h-10 w-10 text-slate-400 " />
        </button><button class="absolute right-0 top-24 z-50 md:right-32" onclick={nextSlide}
            ><ChevronRight class="h-10 w-10" /></button
        >
        <div class="absolute right-4 top-48 flex space-x-2 md:right-80">
            {#each Array(totalSlides) as _, index}
                <button
                    class="h-2 w-2 rounded-full bg-flamingo-500 {index === currentSlide
                        ? 'bg-flamingo-500'
                        : 'bg-white'}"
                    onclick={() => {
                        currentSlide = index;
                        scrollToCurrentSlide();
                    }}
                ></button>
            {/each}
        </div>
    </div>
</section>
Rich-Harris commented 1 month ago

This still isn't a reproduction as described in https://github.com/sveltejs/kit/issues/12209#issuecomment-2105937653. There's nothing we can do with this information.

eftichis0202 commented 1 month ago

Hi Rich, sorry about that - i was able to find the issue with @dummdidumm guidance, the hydration error came up because i had inserted html from a string in {@html article.descriptionPath}. Thank you for your time. Best, Felix