如何在SvelteKit中动态渲染数据库存储的MDX内容?
SvelteKit + SQLite3 动态渲染数据库中MDX内容的解决方案
问题核心
你当前方案的失效原因很直接:
- Svelte编译出的JS是组件的运行时逻辑代码,
{@html}只能渲染静态HTML,根本不会执行这些JS,自然无法渲染<Chart />这类Svelte组件。 - mdsvex的用法有误,不需要嵌套调用
preprocess: mdsvex(),mdsvex自身的compile方法就可以直接完成MDX到Svelte代码的转换。
可行解决方案(客户端动态渲染)
1. 调整服务端:只做MDX到Svelte的转换
服务端只负责把MDX转成标准Svelte代码,不做后续JS编译,把结果传给客户端处理:
/src/routes/test/+page.server.ts
import type { PageServerLoad } from "./$types" import { compile } from "mdsvex"; export const load: PageServerLoad = async () => { const source = ` <script> import Chart from '$lib/components/Chart.svelte'; </script> # Hello friends <Chart /> `; // MDX 直接编译为 Svelte 代码 const { code: svelteCode } = await compile(source, { extensions: ['.mdx', '.svx'], }); return { svelteCode }; }
2. 客户端:动态编译并挂载组件
在客户端用Svelte编译器处理服务端传来的Svelte代码,实例化组件并挂载:
/src/routes/test/+page.svelte
<script lang="ts"> import { compile } from 'svelte/compiler'; import { onMount } from 'svelte'; export let data; let container: HTMLElement; onMount(async () => { if (!container || !data.svelteCode) return; // 编译Svelte代码为可执行模块 const result = compile(data.svelteCode, { generate: 'dom', format: 'esm' }); // 动态导入编译后的组件 const module = await import(`data:text/javascript,${encodeURIComponent(result.js.code)}`); const Component = module.default; // 将组件挂载到页面容器 new Component({ target: container, props: {} }); }); </script> <div bind:this={container}></div>
生产环境优化方案
如果MDX内容较多,客户端编译会拖慢性能,建议在服务端完成全流程编译,把可执行的JS组件代码存在数据库,客户端直接加载:
服务端预编译全流程
/src/routes/test/+page.server.ts
import type { PageServerLoad } from "./$types" import { compile as mdsvexCompile } from "mdsvex"; import { compile as svelteCompile } from 'svelte/compiler'; export const load: PageServerLoad = async () => { const source = ` <script> import Chart from '$lib/components/Chart.svelte'; </script> # Hello friends <Chart /> `; // MDX -> Svelte const { code: svelteCode } = await mdsvexCompile(source, { extensions: ['.mdx', '.svx'], }); // Svelte -> 可执行ESM代码 const { js } = svelteCompile(svelteCode, { generate: 'dom', format: 'esm', filename: 'dynamic-post.mdx' }); return { componentCode: js.code }; }
客户端直接加载组件
/src/routes/test/+page.svelte
<script lang="ts"> import { onMount } from 'svelte'; export let data; let container: HTMLElement; onMount(async () => { if (!container || !data.componentCode) return; // 直接导入预编译好的组件代码 const module = await import(`data:text/javascript,${encodeURIComponent(data.componentCode)}`); const Component = module.default; new Component({ target: container, props: {} }); }); </script> <div bind:this={container}></div>
内容的提问来源于stack exchange,提问作者Joey
相关产品推荐
相关产品推荐

