Search code examples
sveltekitsvelte-component

Display all svelte components in a folder


I have a couple of svelte components in a folder and I wish to display in a single page all the components in that folder.

The only way I've found is creating an index.ts file in that folder and then reference that index file. But that implies maintaining that file whenever I add or remove files.

I found a close answer but have not been able to make it work:

It goes something like this:

<script lang="ts">
    const icons = import.meta.glob('$lib/icons/*.svelte');
</script>

{#await icons}
    {#each icons as Icon}
        <Icon class="w-8 h-8" />
    {/each}
{/await}

This is trying to reference the answer in this page: How can I get all files in a directory with svelte?

Any pointers?


Solution

  • Two main things of note:

    • Glob imports return a mapping from import path to imported value, not just the values.
    • Svelte components use the default export. On dynamic imports you get the entire module which means you have to explicitly retrieve default.

    You can also make the import immediate by using the eager option if you want to. (Without the option, the icons will not server-side render due to #await.)

    Should be something along the lines of this:

    <script lang="ts">
        import type { ComponentType } from 'svelte';
    
        const icons: Record<string, { default: ComponentType }> =
            import.meta.glob('$lib/icons/*.svelte', { eager: true });
    </script>
    
    {#each Object.values(icons) as { default: Icon }}
        <Icon />
    {/each}
    

    Without eager, the values are individual functions which import the component module. So the #await is inside the #each.

    <script lang="ts">
        import type { ComponentType } from 'svelte';
    
        const iconImports = import.meta.glob('$lib/icons/*.svelte') as
            Record<string, () => Promise<{ default: ComponentType }>>;
    </script>
    
    {#each Object.values(iconImports) as importIcon}
        {#await importIcon() then { default: Icon }}
            <Icon />
        {/await}
    {/each}