Svelte/SvelteKit: Dynamic import of components with variable

Viewed 4240

I want to dynamically import components without importing a specific component. I want to set the component name with a variable, received from the store:

<script lang="ts">
    // SVELTE
    import { onMount } from 'svelte';

    // STORE
    import { dynamicComponent } from '$stores/dynamicTitle';


    $: $dynamicComponent;
    console.log($dynamicComponent)

    
    let renderDynamicComponent
    

    onMount(async () => {       
        const importValue = (await import(`../../lib/components/Home/DynamicComponents/${String($dynamicComponent)}.svelte`)).default;
        // const importValue = (await import(`../../lib/components/Home/DynamicComponents/IntroSectionCustom.svelte`)).default;
        renderDynamicComponent = importValue
    });

<svelte:component this={renderDynamicComponent}/>

But I get:

Uncaught (in promise) TypeError: Failed to fetch dynamically imported module: http://localhost:3000/src/lib/components/Home/DynamicComponents/Intro-Section-Custom.svelte

I do not understand. From the error, it seems to be the right path ...

3 Answers

I don't think Svelte + the bundler currently support dynamically generated paths:

let thing = 'Thing';
Thing = (await import(`./${thing}.svelte`)).default; // this won't work
Thing = (await import(`./Thing.svelte`)).default; // this will work

limitation of the bundler.
github issue: https://github.com/sveltejs/svelte/issues/6702

The Rollup plugin @rollup/plugin-dynamic-import-vars might be of help here. I haven't used it with SvelteKit specifically, but it worked fine with standard Svelte with Vite as bundler.

// Example.svelte
function importLocale(locale) {
  return import(`./locales/${locale}.js`);
}
// vite.config.js
import dynamicImportVars from '@rollup/plugin-dynamic-import-vars';

export default (mode) =>
  defineConfig({
    plugins: [
      dynamicImportVars({
        include: './src/Example.svelte'
      })
    ]
});

SvelteKit uses Vite behind the scenes, but has its own configuration format. In svelte.config.js, pass dynamicImportVars() to the config.vite.plugins key:

// svelte.config.js
/** @type {import('@sveltejs/kit').Config} */
const config = {
  vite: {
    plugins: [
      dynamicImportVars({
        include: './src/Example.svelte'
      })
    ]
  }
};

export default config;

Please take note of the limitations mentioned in the README of the Rollup plugin.

What you're doing does work if not using import vars. When adding an import variable you need make your renderDynamicComponent identifier reactive. So instead of this:

let renderDynamicComponent

Do this:

$: renderDynamicComponent = null

This will allow svelte:component to render your imported component with dynamic path variable. This seems to be a special case when using dynamic import vars with Vite.

Related