sveltekit adds new page on top of old one
Asked Answered
R

3

7

I just got a really unexpected bug in my sveltekit application and I can't find anything online talking about it

I have a normal sveltekit application but instead of hydrating the new code when navigating to a new page, it just adds the new code on top of the old one, when i refresh the page it removes the old code (from the previous page)

Edit: after a little bit more exploring I realized it only happens on one page, what part of my code could make this happen?

Rna answered 21/11, 2021 at 0:45 Comment(3)
Could you show us your code, please?Substandard
İt happens with me [_id]/[_id] like routes when page routeing sometimes. But can't really replicate itHitlerism
I have the same problem. Have created another question hereCraniometer
C
4

I had the same issue when having a page loading indicator on SvelteKit for internal navigating. Any page DOM modification, to display the loading indicator during the page navigating, caused the paged appearing twice error. The workaround was to not modify the page during the navigating and use only CSS to display, animate and hide the loading indicator.

Here is my loading indicator code and Here is my documentation regarding the issue. I am not sure if this an internal bug in SvelteKit, so I did not file any bug reports, as I do not have a clean repeatable example. You can also see the fixed page loading indicator on the action on this page if you click any of the blockchains.

<script>
    /**
     * Svelte does not give a load indication if you hit a link that leads to a page with slow load() function.
     * Svelte uses internal router, not server-side loading.
     * Thus, we need to manually give some indication in the user interface if the loading takes more than a blink of an eye.
     *
     * The component is originally made for https://tradingstrategy.ai
     *
     * Based on the original implementation https://github.com/shajidhasan/sveltekit-page-progress-demo by Shajid Hasan.
     *
     * As this component is absolutely position, you can put it at any part of your __layout.svelte.
     */
    import { onDestroy, onMount } from 'svelte';
    import { writable } from 'svelte/store';
    import { tweened } from 'svelte/motion';
    import { cubicOut } from 'svelte/easing';

    const navigationState = writable();

    const progress = tweened(0, {
        duration: 3500,
        easing: cubicOut
    });

    const unsubscribe = navigationState.subscribe((state) => {

        // You will always get state=undefined
        // event on the server-side rendering, so
        // safely ignore it
        //console.log("The loading state is", state);

        if (state === 'loading-with-progress-bar') {
            progress.set(0, { duration: 0 });
            progress.set(0.8, { duration: 5000 });
        } else if (state === 'loaded') {
            progress.set(1, { duration: 1000 });
        }
    });

    onMount(() => {
        // progress.set(0.7);
    });
    onDestroy(() => {
        unsubscribe();
    });
</script>

<!-- See the (little) documentation of special SvelteKit events here https://kit.svelte.dev/docs#events -->
<svelte:window
    on:sveltekit:navigation-start={() => {

        // If the page loads fast enough in the preloading state,
        // never display the progress bar
        $navigationState = 'preloading';

        // Delay the progress bar to become visible an eyeblink... only show if the page load takes too long
        setTimeout(function() {
            // After 250ms switch preloading to loading-with-progress-bar
            if($navigationState === 'preloading') {
                $navigationState = 'loading-with-progress-bar';
            }
        }, 500);
    }}
    on:sveltekit:navigation-end={() => {
        $navigationState = 'loaded';
    }}
/>

<!--
    Make sure the container component is always in the DOM structure.

    If we make changes to the page structure during the navigation, we get a page double render error:
    https://mcmap.net/q/1496699/-sveltekit-adds-new-page-on-top-of-old-one

    Not sure if this is a bug or a feature.
    Thus, make sure any progress animation is done using CSS only.
-->
<div class="page-progress-bar" class:loaded={$navigationState === 'loaded'} class:preloading={$navigationState === 'preloading'} class:loading={$navigationState === 'loading-with-progress-bar'}>
    <div class="progress-sliver" style={`--width: ${$progress * 100}%`} />
</div>

<style>
     /* Always stay fixed at the top, but stay transparent if no activity is going on */
    .page-progress-bar {
        position: fixed;
        top: 0;
        left: 0;
        right: 0;
        height: 0.5rem;
        background: transparent;
        z-index: 100;
        opacity: 0;
        transition: opacity 0.5s;
    }

     /* After transitioning from preloading to loading state, make the progress bar visible with CSS transition on opacity */
    .page-progress-bar.loading {
        opacity: 1;
        transition: opacity 0.5s;
    }

    .progress-sliver {
        width: var(--width);
        background-color: var(--price-up-green);
        height: 100%;
    }
</style>
Chloris answered 10/12, 2021 at 20:30 Comment(0)
C
3

I also saw this issue with the transition directive. The new page loads while the exit animation is playing. I used local transitions to solve this.

https://svelte.dev/tutorial/local-transitions

Concordant answered 10/12, 2021 at 20:36 Comment(0)
K
1

I had the same issue trying to implement an auth component. I figured out a workaround, and that was to add out:fade={{duration:0}} in the component. I found that this happens mostly on pages with many {#if} blocks, but this isn't always the case. Here is an example of how I implemented the fix. Please note, I am using Fireabse, so you may have to adapt this.

Auth.svelte

    <script lang="ts">
        import { onAuthStateChanged, getAuth } from "firebase/auth";
        import { fade } from "svelte/transition";
        import { getApp } from "$lib/firebase";
        import { onMount } from "svelte";
        import { goto } from "svelte/navigation";

        const auth = getAuth(getApp());
        let isLoggedIn = false;
        let isLoading = true;
    
        onMount(()=>{
            isLoading = false;
            return onAuthStateChanged(auth, (user)=>{
                isLoggedIn = !!user;
                // or whatever your login page is
                if (!isLoggedIn) goto("/login")
            });
        });
    </script>
    {#if isLoggedIn && !isLoading}
       <div out:fade={{duration:0}}>
            <slot></slot>
        </div>
    {:else if isLoading && !isLoggedIn}
        <div></div>
    {/if}
Kurtzman answered 25/3, 2023 at 20:22 Comment(1)
The getApp function from $lib/firebase is a custom function that checks for existing apps, if found, returns the first one, otherwise it uses initilalizeApp with the config and returns that instead.Kurtzman

© 2022 - 2024 — McMap. All rights reserved.