SvelteKit SSR失效求助:未禁用SSR但无服务端渲染内容
问题描述
使用Svelte 5 + TypeScript,未在页面或全局设置export const ssr = false,但所有页面初始GET请求返回的HTML仅包含客户端渲染脚本,无实际页面内容,导致SEO工具无法识别页面内容。
配置信息
Vite配置
import { sveltekit } from '@sveltejs/kit/vite'; import { defineConfig } from 'vitest/config'; export default defineConfig({ plugins: [sveltekit()], test: { include: ['src/**/*.{test,spec}.{js,ts}'] }, worker: { format: "es" }, });
Svelte配置
import adapter from '@sveltejs/adapter-node'; import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; /** @type {import('@sveltejs/kit').Config} */ const config = { preprocess: vitePreprocess(), kit: { adapter: adapter(), files: { hooks: { client: 'src/lib/client/hooks.client', server: 'src/lib/server/hooks.server' }, appTemplate: 'src/lib/client/app.html', errorTemplate: 'src/lib/client/error.html', serviceWorker: 'src/lib/client/service-worker' }, } }; export default config;
返回的HTML示例
<body data-sveltekit-preload-data="hover"> <div style="display: contents"><!--[--><!--[--><!----><!--[!--><!--]--><!----><!--]--><!--[!--><!--]--><!--]--> <script> { __sveltekit_dev = { base: new URL(".", location).pathname.slice(0, -1), env: {"PUBLIC_APP_ID":"0e4800----6b739","PUBLIC_FIREBASE_ALIAS":"m---tchi","PUBLIC_FIREBASE_ROOT_FOLDER":"--e-i","PUBLIC_FIREBASE_STORAGE_BUCKET":"me000----spot.com","PUBLIC_TELEGRAM_BOT_TOKEN":"715749------K_c","PUBLIC_TELEGRAM_CHAT_ID":"-----"} }; const element = document.currentScript.parentElement; const data = [{"type":"data","data":{"claims":void 0},"uses":{"dependencies":["app:user"]}},{"type":"data","data":null,"uses":{"dependencies":["app:room"]}}]; Promise.all([ import("/@fs/C:/AISocialMedia/aisocial/node_modules/@sveltejs/kit/src/runtime/client/entry.js"), import("/@fs/C:/AISocialMedia/aisocial/.svelte-kit/generated/client/app.js") ]).then(([kit, app]) => { kit.start(app, element, { node_ids: [0, 3], data, form: null, error: null }); }); } </script> </div> </body>
排查与解决方案
检查自定义app.html模板:确认
src/lib/client/app.html中包含%sveltekit.body%占位符。SvelteKit依赖这个占位符注入SSR渲染的页面内容,如果缺失,会导致返回的HTML没有实际页面内容。正确模板示例:<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> %sveltekit.head% </head> <body> %sveltekit.body% </body> </html>检查server hooks逻辑:查看
src/lib/server/hooks.server.ts中的handle函数,确保正确调用resolve(event)并返回响应。如果函数中存在错误处理、重定向逻辑未正确返回,可能会中断SSR流程。正确逻辑示例:export async function handle({ event, resolve }) { // 自定义业务逻辑 const response = await resolve(event); return response; }排查组件中的客户端API使用:检查所有路由、layout组件,确保没有在顶层(非
onMount、非browser条件判断下)使用window、document等浏览器专属API。这类API在SSR阶段会抛出错误,导致SvelteKit fallback到纯客户端渲染。修复示例:<script> import { browser } from '$app/environment'; import { onMount } from 'svelte'; // 方式1:使用browser条件判断 if (browser) { // 调用window相关API } // 方式2:使用onMount钩子 onMount(() => { // 调用window相关API }); </script>升级SvelteKit版本:Svelte 5处于beta阶段,可能存在已知的SSR相关Bug。执行
npm update @sveltejs/kit @sveltejs/adapter-node升级到最新beta版本,排查是否为版本兼容性问题。验证全局SSR配置:检查根
layout.ts或layout.server.ts中是否意外设置了export const ssr = false,再次确认避免遗漏。检查构建与运行流程:使用adapter-node时,确保先执行
npm run build构建项目,再通过node build启动服务。开发环境下尝试重启服务、清除缓存后测试。
内容的提问来源于stack exchange,提问作者demonjoseph

