This library enables compiling Svelte components from text at runtime, allowing dynamic, user-provided svelte component code to be compiled and mounted in the browser.
<script lang="ts">
let { counter } = $props();
console.log("Component loaded");
</script>
<div class="component">
<h2 class="title">Clicked {counter} times</h2>
</div>
<style>
.component {
display: flex;
justify-content: center;
}
.title {
color: #333333;
}
</style>
The above code is an example of a string that can be compiled and loaded at runtime.
npm install @mrgentle/svelte-runtime-components
Compile code on the server:
//+page.server.ts
import lock from "../../package-lock.json" with { type: "json" };
import { compileModule } from "@mrgentle/svelte-runtime-components/compiler"
const template = `
<script lang="ts">
...
`;
export const load = async () => {
const { client } = await compileModule(template, lock.packages['node_modules/svelte'].version);
return {
clientModule: client
};
}
svelte/compiler to compile component source code.compileModule returns a client ES module as a string, ready to execute in the browser via dynamic import().
<!-- +page.svelte -->
<script lang="ts">
import { mountComponent, type RuntimeComponent } from '$lib/loader.js';
import { onMount } from 'svelte';
let { data } = $props();
let mountRef: HTMLElement;
let dynamicComponent: RuntimeComponent;
let counter = $state(0);
onMount(async () => {
dynamicComponent = await mountComponent(data.clientModule, mountRef, { counter });
})
</script>
<div bind:this={mountRef}></div>
mountComponent is a lightweight browser utility that loads and mounts the compiled component.
Returns a wrapped RuntimeComponent.
This is the built-in wrapper
import ComponentBody from 'component-body';
import { hydrate, mount, unmount } from "svelte";
export default function factory(target: HTMLElement, props: object) {
const component = mount(ComponentBody, { target, props });
return {
component,
name: "RuntimeComponent",
props,
destroy: () => unmount(component),
setProps: (props: object) => {
hydrate(ComponentBody, { target, props });
}
};
};
The wrapper exposes setProps which allows you to hydrate the component with new props.
You can write your own wrappers for use with compileModule Just make sure you include this line so that the esbuild plugin finds the component body:
import ComponentBody from 'component-body';
Huge thanks to mateothegreat for his help! Check out their project Svelte dynamic component engine as well