Search code examples
sveltesvelte-3svelte-component

How to bind compiled result of string to component in Svelte


I am trying to write a component which has a source string property. Then, users can set the source and my component compiles and renders the source.

Both SPA and SSR should be supported for compiling and rendering.

Here is the usage of my component in App.svelte:

<script>
    import Preview from './Preview.svelte'
    const source = '<div {...$$restProps}><slot /></div>'
    let name = 'world';
</script>

<Preview {source}>Hello {name}!</Preview>

And the Preview.svelte:

<script>
    import { compile } from 'svelte/compiler'
    export let source
    const cmp = compile(source, {
        filename: 'Component.svelte',
        format: 'esm',
        // generate: 'ssr'
    })
    console.log(cmp.js.code, cmp.css.code)
</script>

How can I bind the compiled result to a component?

I am thinking something like this:

<svelte:component this={cmp.something} />

I tried the REPL, but it has error:

Could not load https://unpkg.com/[email protected]/compiler/index.mjs (imported by ./Preview.svelte): Cannot find "/compiler/index.mjs" in [email protected]


Solution

  • You can't import the compiler like that in the REPL because it does not respect the exports of the package.json. It falsely assumes that svelte/compiler refers to a directory, though the files are at the package root:

    "exports": {
        // ...
        "./compiler": {
          "types": "./types/compiler/index.d.ts",
          "import": "./compiler.mjs",
          "require": "./compiler.js"
        },
    }
    

    The given code works as expected locally e.g. in a SvelteKit project.

    As a workaround you can change the import to a full URL:

    import { compile } from 'https://unpkg.com/[email protected]/compiler.mjs';
    

    How to one can load the compiled component code is explained in this answer.