Home > Net >  SvelteKit async function load not working or Firebase onAuthStateChanged cannot be made blocking
SvelteKit async function load not working or Firebase onAuthStateChanged cannot be made blocking

Time:07-15

I am building a website with SvelteKit. My auth provider is Firebase. I am trying to protect some pages with Authentication, so I am programming an auth listener in __layout.svelte. However, no matter how I try, I can't seems to pass the Auth Status from the context module to my script, this is my code:

__layout.svelte

<script lang="ts" context="module">
    import type { User } from 'firebase/auth';
    import { onAuthStateChanged } from "firebase/auth";
    import { auth } from "$lib/scripts/firebaseStart";

    export async function load() {
        let authUser: User|boolean = await getAuthUser();
        async function getAuthUser() {
            await onAuthStateChanged(auth, (user) => {
                // let authUser: User|undefined;
                if (user) {
                    // User is signed in, see docs for a list of available properties
                    // https://firebase.google.com/docs/reference/js/firebase.User
                    authUser = user;
                    console.log(authUser); // logs authUser out as I expected it to
                    // ...
                } else {
                    // User is signed out
                    // ...
                    authUser = false;
                }
            });
            return authUser;
        }

        return {
            props: { authUser }
        };
    }
</script>

<script lang="ts">
    export let authUser: User|boolean;
    console.log(authUser); // logs undefined and executed before the above console log
</script>

The conclusion I get is that the code in script tag is executed before the context=module could return the props. How do I make the code in the context module 'blocking'?

CodePudding user response:

load always runs before the component is created, your code is incorrect.

onAuthStateChanged is not awaitable and returns an unsubscribe function instead. Also, you should either set the local authUser variable or return it from the function, doing both is unnecessary/confusing.

You can turn onAuthStateChanged into something that can be awaited by using the Promise constructor like this:

export async function load() {
    const authUser: User | boolean = await getAuthUser();

    function getAuthUser() {
        return new Promise(resolve => {
            onAuthStateChanged(
                auth,
                user => resolve(user ? user : false)
            );
        });
    }

    return {
        props: { authUser }
    };
}

Note that onAuthStateChanged can be called multiple times and this only captures the first change. If you want to continuously track the auth state you should update a store.

  • Related