禁用CSR后,如何在SvelteKit中运行客户端脚本并保留预渲染导航栏?
解决方案1:分离服务端数据与客户端逻辑,规避 hydration 报错
核心思路是把服务端数据获取逻辑与客户端交互逻辑彻底分开,确保客户端不会执行服务端专属代码(如fs),同时保留预渲染内容并启用CSR。
将目录列表生成移至服务端
load函数
创建布局的服务端load脚本,预渲染时执行并传递数据:// src/routes/+layout.server.js import fs from 'fs/promises'; import path from 'path'; export async function load() { // 仅在预渲染/服务端执行,获取目录列表 const dirs = await fs.readdir(path.join(process.cwd(), 'src/routes')); return { dirs }; }在布局组件中接收并渲染预渲染内容
直接使用服务端传递的数据渲染导航栏,客户端 hydration 时不会重复执行服务端逻辑:<!-- src/routes/+layout.svelte --> <script> export let data; </script> <nav> {#each data.dirs as dir} <a href="/{dir}">{dir}</a> {/each} </nav> <slot />在目标组件中用
onMount执行客户端逻辑
仅在客户端环境中运行Github数据获取代码:<!-- src/routes/code/+page.svelte --> <script> import { onMount } from 'svelte'; let codeContent = ''; onMount(async () => { // 仅客户端执行的请求逻辑 const res = await fetch('https://api.github.com/your-repo-path'); codeContent = await res.text(); }); </script> <pre>{codeContent}</pre>
解决方案2:禁用全局CSR,为特定组件注入客户端脚本
如果必须全局禁用CSR,可通过纯客户端脚本或client:only指令让目标组件运行交互逻辑:
全局禁用CSR
在页面/布局配置中关闭CSR:// src/routes/+page.js export const csr = false;为目标组件添加纯客户端脚本
直接在组件中嵌入客户端执行的脚本,预渲染时仅保留容器,客户端加载后填充内容:<!-- src/routes/code/+page.svelte --> <div id="code-container"></div> <script> async function loadCode() { const res = await fetch('https://api.github.com/your-repo-path'); const code = await res.text(); document.getElementById('code-container').textContent = code; } // 页面加载后执行 window.addEventListener('load', loadCode); </script>或使用
client:only组件隔离客户端逻辑
创建仅在客户端渲染的组件,通过client:only指令引入:<!-- src/lib/ClientCodeViewer.svelte --> <script> import { onMount } from 'svelte'; let code = ''; onMount(async () => { const res = await fetch('https://api.github.com/your-repo-path'); code = await res.text(); }); </script> <pre>{code}</pre>在页面中引入时添加指令:
<!-- src/routes/code/+page.svelte --> <nav> <!-- 预渲染的导航栏内容 --> </nav> <svelte:component this={ClientCodeViewer} client:only />
关键注意事项
- 所有服务端专属逻辑(如
fs操作)必须放在.server.js后缀的load函数中,绝对不能在组件顶层脚本中直接使用,避免客户端 hydration 报错。 - 客户端交互逻辑必须用
onMount或纯HTML脚本包裹,确保仅在浏览器环境执行。 - 若禁用全局CSR,Svelte的生命周期钩子不会触发,需依赖原生浏览器事件或
client:only实现客户端逻辑。
内容的提问来源于stack exchange,提问作者Fasteroid
相关产品推荐
相关产品推荐

