如何在SvelteKit中通过[slug]参数加载HTML页面内容?
SvelteKit加载本地HTML文件内容的正确方式
项目结构
src lib cms projects slug1.html slug2.html routes projects [slug] +page.server.js +page.svelte
需求:用户访问https://example.com/projects/slug1时,加载对应slug1.html的内容并展示在页面中。
错误代码与报错信息
你之前在+page.server.js中写的代码:
/** @type {import ('./$types').PageServerLoad } */ export async function load({ params }) { console.log(params); return { project: await import(`../../../lib/cms/projects/${params.slug}.html?raw`), }; }
尝试在+page.svelte中用{@html data.project}展示时,出现如下报错:
Error: Data returned from `load` while rendering /projects/[slug] is not serializable: Cannot stringify POJOs with symbolic keys (data.project) at get_data (/Users/me/Documents/Repositories/site/node_modules/@sveltejs/kit/src/runtime/server/page/render.js:592:9) at Module.render_response (/Users/me/Documents/Repositories/site/node_modules/@sveltejs/kit/src/runtime/server/page/render.js:264:27) at async Module.render_page (/Users/me/Documents/Repositories/site/node_modules/@sveltejs/kit/src/runtime/server/page/index.js:286:10) at async resolve (/Users/me/Documents/Repositories/site/node_modules/@sveltejs/kit/src/runtime/server/respond.js:446:18) at async Module.respond (/Users/me/Documents/Repositories/site/node_modules/@sveltejs/kit/src/runtime/server/respond.js:319:20) at async file:///Users/me/Documents/Repositories/site/node_modules/@sveltejs/kit/src/exports/vite/dev/index.js:524:22
问题根源
用import加载带?raw后缀的文件时,返回的是一个模块对象(而非纯文本字符串),这个对象包含Symbol类型的键,而SvelteKit要求load函数返回的数据必须是可序列化的(能转换为JSON格式),这类带Symbol键的对象无法被序列化,因此触发了报错。
正确解决方案
在+page.server.js中直接用Node.js的文件系统模块读取HTML文件内容,因为+page.server.js运行在服务器端,拥有文件系统访问权限:
修改后的+page.server.js代码
import { readFile } from 'node:fs/promises'; import { join } from 'node:path'; import { fileURLToPath } from 'node:url'; import { error } from '@sveltejs/kit'; /** @type {import ('./$types').PageServerLoad } */ export async function load({ params }) { // 获取当前文件所在目录的绝对路径 const __dirname = fileURLToPath(new URL('.', import.meta.url)); // 拼接HTML文件的绝对路径 const filePath = join(__dirname, '../../../lib/cms/projects', `${params.slug}.html`); try { // 读取文件内容为字符串 const projectContent = await readFile(filePath, 'utf8'); return { project: projectContent }; } catch (err) { // 如果文件不存在,抛出404错误 throw error(404, 'Project not found'); } }
+page.svelte中的用法
保持原来的写法即可:
<script> /** @type {import('./$types').PageData} */ export let data; </script> {@html data.project}
说明
- 使用
readFile直接读取文件内容,返回的是纯字符串,完全符合SvelteKit的序列化要求。 - 通过
fileURLToPath和join拼接绝对路径,避免了相对路径在不同环境下的问题。 - 增加了错误捕获,当请求的slug对应的HTML文件不存在时,返回404页面,提升用户体验。
内容的提问来源于stack exchange,提问作者Nicholas Pappas
相关产品推荐
相关产品推荐

