I’m creating a resume builder where many templates will be possible. I have a component that switches between the different templates depending on what the user chose. For now I only have three templates, but the file already compiles to 300Kb:
<script>
import Student from '$lib/template/_student/Home.svelte';
import Expert from '$lib/template/_expert/Home.svelte';
import Artist from '$lib/template/_artist/Home.svelte';
export let doc;
$: templateId = doc?.templateId
$: cssUrl = doc?.design?.color?.substring(1)
</script>
<div id='templateLoader'>
{#if templateId == '1'}
<Student {doc} on:modified/>
{:else if templateId == '2'}
<Expert {doc} on:modified/>
{:else if templateId == '3'}
<Artist {doc} on:modified/>
{:else}
<Expert {doc} on:modified/>
{/if}
</div>
<svelte:head>
<link rel="stylesheet" href={`/css/design.css?t=${templateId}&c=${cssUrl}`} />
</svelte:head>
I had an onMount() function that was loading the template dynamically, but that was a very unpleasant user experience (and it’s not good for SEO)
I was wondering if it is possible to tell SvelteKit to keep each template in a separate file, and to loda that file with an additional server request () which in SSR is unnoticable) after the {#if templateId}
section is processed. In Next.js there is a dynamic import mechanism for that.
Any suggestions? I’m planning to have dozens of templates, so I cannot keep things this way.
Just to compare with other comps, this component alone is huge:
.svelte-kit/output/client/_app/immutable/chunks/ToolbarButton-5e81536b.js
11.11 kB │ gzip: 3.69 kB .svelte-kit/output/client/_app/immutable/components/pages/authorized/cv/ai/_page.svelte-d03f5080.js
14.39 kB │ gzip: 4.99 kB .svelte-kit/output/client/_app/immutable/chunks/TemplateDetector-88b690e9.js
305.29 kB │ gzip: 82.38 kB
Ideally, the solution would look like this:
<script>
export let doc;
$: templateId = doc?.templateId
$: cssUrl = doc?.design?.color?.substring(1)
function getTemplatePath(templateId) {
switch( templateId ) {
case '1' :
return '$lib/template/_student/Home.svelte'
case '2' :
return '$lib/template/_expert/Home.svelte'
case '3' :
return '$lib/template/_artist/Home.svelte'
default :
return '$lib/template/_expert/Home.svelte'
}
}
$: Template = null
import(getTemplatePath(templateId) /* @vite-ignore */).then(loaded => Template = loaded)
</script>
<div id='templateLoader'>
<Template {doc} on:modified/>
</div>
<svelte:head>
<link rel="stylesheet" href={`/css/design.css?t=${templateId}&c=${cssUrl}`} />
</svelte:head>
But this throws a series of exceptions:
const err = new Error(`Cannot find module '${id}' imported from '${importer}'`);
^
Error: Cannot find module '$lib/template/_expert/Home.svelte' imported from 'C:/Users/zhamd/work/linkedinCv-back/src/lib/template/TemplateDetector.svelte'
at nodeImport (file:///C:/Users/zhamd/work/linkedinCv-back/node_modules/.pnpm/[email protected]/node_modules/vite/dist/node/chunks/dep-c167897e.js:54014:25)
at ssrImport (file:///C:/Users/zhamd/work/linkedinCv-back/node_modules/.pnpm/[email protected]/node_modules/vite/dist/node/chunks/dep-c167897e.js:53935:20)
at ssrDynamicImport (file:///C:/Users/zhamd/work/linkedinCv-back/node_modules/.pnpm/[email protected]/node_modules/vite/dist/node/chunks/dep-c167897e.js:53962:16)
at eval (/src/lib/template/TemplateDetector.svelte:26:2)
at Object.$$render (/node_modules/.pnpm/[email protected]/node_modules/svelte/internal/index.mjs:2042:22)
at eval (/src/routes/cv/[id]/+page.svelte:49:147)
at Object.$$render (/node_modules/.pnpm/[email protected]/node_modules/svelte/internal/index.mjs:2042:22)
at Object.default (/.svelte-kit/generated/root.svelte:102:133)
at eval (/src/routes/+layout.svelte:26:33)
at Object.$$render (/node_modules/.pnpm/[email protected]/node_modules/svelte/internal/index.mjs:2042:22) {
code: 'ERR_MODULE_NOT_FOUND'
}
2
Answers
Just to followup after the answer of Tonton-Blax, this is how I ended up doing it:
Svelte components can be loaded dynamically with standard async import methods (
await import (`./${yourComponent}.svelte`)
Roughly based on your example you could do something of the like, but there’s plenty of way to achieve this.
This article goes a bit more into detail if needed.