Search code examples
sveltekitsvelte-3

Returning Svelte components with Sveltekit server load function


I'm new to Sveltekit, and having issues trying to return Svelte components from the server.

I'm migrating settings for a nav menu in Sveltekit from a client-side .svelte component to a server load() function.

Currently, I have a nav menu in routes/+layout.svelte, and use a dict to define the menu items. The icons for each menu item are svelte components from a 3rd party library.

Current Working Example

//routes/+layout.svelte
<script>
    import {ArrowLeftOnRectangleIcon, Cog6ToothIcon, UserCircleIcon} from "@babeard/svelte-heroicons/mini";
    import NavMenu from "@components/NavMenu.svelte";

    const menuSettings = {
        menuButtonIcon: UserCircleIcon,
        menuItems: [
            {title: 'Settings', icon: Cog6ToothIcon, url: '/app/settings', current: false},
            {title: 'Sign Out', icon: ArrowLeftOnRectangleIcon, url: '/app/sign-out',  current: false},
        ]
    }
</script>

<NavMenu {...menuSettings} />
<slot />

I now want to move those menu settings to a server load() function, so that I can determine which menu items to show server-side.

Proposed (not working) example

<!--routes/+layout.svelte-->
<script>
    import NavMenu from "@components/NavMenu.svelte";

    export let data;
</script>

<NavMenu {...data.menuSettings} />
<slot />
//routes/+layout.server.js

import {ArrowLeftOnRectangleIcon, Cog6ToothIcon, UserCircleIcon} from "@babeard/svelte-heroicons/mini";

export function load() {
    return {
        menuSettings: {
            menuButtonIcon: UserCircleIcon,
            menuItems: [
                {title: 'Settings', icon: Cog6ToothIcon, url: '/app/settings', current: false},
                {title: 'Sign Out', icon: ArrowLeftOnRectangleIcon, url: '/app/sign-out',  current: false},
            ]
        }
    }
}

This throws an error:

Error: Data returned from `load` while rendering / is not serializable: Cannot stringify a function (data.menuSettings.menuButtonIcon)

Is there a way to return components from a load() function? And if not, what would be the best way to approach this issue?


Solution

  • I would probably give the icons a key, return said key from the load function and resolve the component on the page.

    const icons = {
      'user-circle': UserCircleIcon,
      'cog-6-tooth': Cog6ToothIcon,
      // ...
    }
    
    <svelte:component this={icons[menuSettings.menuButtonIcon]} />
    

    Though I suspect very little actually needs to be determined on the server. Usually it's just determining visibility, so you probably can leave much more on the page itself.