You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

禁用CSR后,如何在SvelteKit中运行客户端脚本并保留预渲染导航栏?

解决方案1:分离服务端数据与客户端逻辑,规避 hydration 报错

核心思路是把服务端数据获取逻辑与客户端交互逻辑彻底分开,确保客户端不会执行服务端专属代码(如fs),同时保留预渲染内容并启用CSR。

  1. 将目录列表生成移至服务端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 };
    }
    
  2. 在布局组件中接收并渲染预渲染内容
    直接使用服务端传递的数据渲染导航栏,客户端 hydration 时不会重复执行服务端逻辑:

    <!-- src/routes/+layout.svelte -->
    <script>
      export let data;
    </script>
    
    <nav>
      {#each data.dirs as dir}
        <a href="/{dir}">{dir}</a>
      {/each}
    </nav>
    <slot />
    
  3. 在目标组件中用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指令让目标组件运行交互逻辑:

  1. 全局禁用CSR
    在页面/布局配置中关闭CSR:

    // src/routes/+page.js
    export const csr = false;
    
  2. 为目标组件添加纯客户端脚本
    直接在组件中嵌入客户端执行的脚本,预渲染时仅保留容器,客户端加载后填充内容:

    <!-- 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>
    
  3. 或使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 04:07:28