23.05-SvelteKit集成Hono
要点
- SvelteKit 内置的
+page.server.ts和+layout.server.ts可以在服务端直接调用 Hono RPC - 客户端使用 Svelte 的
load函数获取数据 - SvelteKit 的表单 actions 可以替代传统的 API 调用
- 配合 Svelte Query 可以实现类似 React Query 的效果
内容
1. SvelteKit 的数据加载模式
SvelteKit 有两种数据加载方式:
服务端加载(推荐):在 +page.server.ts 中获取数据,直接传递给页面组件
客户端加载:在浏览器中使用 fetch 或 Svelte Query
2. 服务端加载(推荐)
2.1 创建 RPC 客户端
// src/lib/api.ts
import { hc } from 'hono/client'
import type { AppType } from '@api/src/index'
export const api = hc<AppType>(import.meta.env.VITE_API_URL)2.2 在 +page.server.ts 中使用
// src/routes/users/[id]/+page.server.ts
import type { PageServerLoad } from './$types'
import { api } from '$lib/api'
export const load: PageServerLoad = async ({ params }) => {
const res = await api.api.users[':id'].$get({
param: { id: params.id },
})
if (!res.ok) {
throw new Error('Failed to fetch user')
}
return {
user: await res.json(),
}
}<!-- src/routes/users/[id]/+page.svelte -->
<script lang="ts">
import type { PageData } from './$types'
export let data: PageData
</script>
<h1>{data.user.name}</h1>
<p>{data.user.email}</p>3. 客户端加载
如果需要客户端加载,使用 Svelte 的 onMount:
<!-- src/components/UserProfile.svelte -->
<script lang="ts">
import { onMount } from 'svelte'
import { api } from '$lib/api'
export let userId: string
let user: any = null
let loading = true
let error: Error | null = null
onMount(async () => {
try {
const res = await api.api.users[':id'].$get({
param: { id: userId },
})
if (!res.ok) {
throw new Error('Failed to fetch')
}
user = await res.json()
} catch (err) {
error = err as Error
} finally {
loading = false
}
})
</script>
{#if loading}
<div>加载中...</div>
{:else if error}
<div>加载失败</div>
{:else if user}
<h1>{user.name}</h1>
<p>{user.email}</p>
{/if}4. 使用 Svelte Query
安装 Svelte Query:
npm install @tanstack/svelte-query配置:
// src/routes/+layout.ts
import { QueryClient } from '@tanstack/svelte-query'
export const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 1000 * 60 * 5,
},
},
})<!-- src/routes/+layout.svelte -->
<script lang="ts">
import { QueryClientProvider } from '@tanstack/svelte-query'
import { queryClient } from './layout.ts'
</script>
<QueryClientProvider client={queryClient}>
<slot />
</QueryClientProvider>使用:
<!-- src/components/UserProfile.svelte -->
<script lang="ts">
import { createQuery } from '@tanstack/svelte-query'
import { api } from '$lib/api'
export let userId: string
const query = createQuery({
queryKey: () => ['user', userId],
queryFn: async () => {
const res = await api.api.users[':id'].$get({
param: { id: userId },
})
if (!res.ok) throw new Error('Failed to fetch')
return res.json()
},
})
</script>
{#if $query.isLoading}
<div>加载中...</div>
{:else if $query.error}
<div>加载失败</div>
{:else if $query.data}
<h1>{$query.data.name}</h1>
<p>{$query.data.email}</p>
{/if}5. 表单 Actions
SvelteKit 的表单 actions 可以替代传统的 API 调用:
// src/routes/chat/+page.server.ts
import type { Actions } from './$types'
import { api } from '$lib/api'
export const actions: Actions = {
sendMessage: async ({ request }) => {
const formData = await request.formData()
const message = formData.get('message') as string
const res = await api.api.chat.$post({
json: { message },
})
if (!res.ok) {
return { success: false, error: '发送失败' }
}
const data = await res.json()
return { success: true, reply: data.reply }
},
}<!-- src/routes/chat/+page.svelte -->
<script lang="ts">
import { enhance } from '$app/forms'
import type { ActionData } from './$types'
export let form: ActionData
</script>
<form method="POST" action="?/sendMessage" use:enhance>
<input name="message" placeholder="输入消息" />
<button type="submit">发送</button>
</form>
{#if form?.success}
<p>回复:{form.reply}</p>
{:else if form?.error}
<p>错误:{form.error}</p>
{/if}6. 小结
SvelteKit 集成 Hono API 的关键点:
- 服务端加载(推荐):在
+page.server.ts中调用 RPC,数据直接传递给页面 - 客户端加载:使用
onMount或 Svelte Query - 表单 Actions:SvelteKit 特有的表单处理方式
- 类型安全:RPC 客户端提供完整的类型推导
一句话带走:
SvelteKit 的服务端加载模式是最简洁的集成方式,数据在
+page.server.ts中获取,直接传递给页面组件。