Use Cases (更新: 2026/6/2)

用Claude Code高效开发Svelte与SvelteKit

面向初学者的Claude Code与Svelte/SvelteKit实战指南,覆盖runes、路由、表单actions、测试和安全改动方式。

用Claude Code高效开发Svelte与SvelteKit

为什么Claude Code适合SvelteKit开发

Svelte是一个把组件编译成轻量JavaScript的UI框架。SvelteKit在它之上提供文件路由、服务端渲染、load函数、表单actions、API端点和部署适配器。对于初学者来说,Svelte的语法很直接,但一个真实功能往往会同时改到 src/routessrc/lib/components$lib/server、类型和测试,这正是Claude Code能发挥作用的地方。

Claude Code是Anthropic官方的agentic coding工具,可以读取代码库、编辑文件、运行命令,并在终端、IDE、桌面和浏览器环境中工作。使用它开发SvelteKit时,关键不是让它“一次生成完整应用”,而是让它先读相关文件,再按小范围修改。这样既能利用AI速度,也能保留人类对路由、权限、数据边界和发布风险的判断。

本文用一个任务管理小应用做例子,讲清楚项目创建、Svelte 5 runes、共享状态、SvelteKit路由、form actions、测试、Claude Code提示词、实际用例和常见坑。runes可以理解为“响应式语法标记”:$props接收父组件输入,$state声明会变化的状态,$derived从状态计算显示值,$effect处理浏览器中的副作用。

flowchart LR
  A["写清小需求"] --> B["让Claude Code读取相关文件"]
  B --> C["修改Svelte组件"]
  C --> D["检查load与actions"]
  D --> E["运行类型检查和测试"]
  E --> F["人工审查git diff"]

项目创建与Claude Code启动

新建SvelteKit项目时,当前官方推荐从Svelte CLI开始,也就是 npx sv create my-app。如果只是做一个独立的Svelte组件应用,也可以用Vite的 svelte-ts 模板。Vite官方指南现在要求Vite运行在Node.js 20.19+或22.12+,如果你的机器还停在旧版本Node,先升级再排查Svelte错误会更省时间。

npx sv create claude-svelte-demo
cd claude-svelte-demo
npm install
npm run dev

claude

第一次让Claude Code进入项目时,建议先用plan mode。这个模式会读取文件和提出计划,但不会直接改源码。

/plan
我想在这个SvelteKit项目中增加任务列表功能。
请先读取src/routes和src/lib,说明需要修改哪些文件、数据如何流动、应该补哪些测试。
现在不要编辑文件。

也可以从命令行直接启动:

claude --permission-mode plan

团队规则应写进 CLAUDE.md.claude/CLAUDE.md。例如:“优先使用Svelte 5 runes”“表单提交使用SvelteKit actions”“秘密信息只能放在 $lib/server”“完成前运行 npm run check”“未经要求不提交commit”。规则越具体,Claude Code越容易遵守。

用Svelte 5写小组件

下面的 TaskCard.svelte 可以直接放到 src/lib/components/TaskCard.svelte。它接收一个任务对象和一个回调函数,用 $derived 计算显示标签。示例保留了按钮的 aria-pressed,因为可访问性不应该在AI改代码时被牺牲。

<!-- src/lib/components/TaskCard.svelte -->
<script lang="ts">
  type Task = {
    id: string;
    title: string;
    done: boolean;
    estimateMinutes: number;
    tags: string[];
  };

  let {
    task,
    onToggle
  }: {
    task: Task;
    onToggle: (id: string) => void;
  } = $props();

  let statusLabel = $derived(task.done ? '已完成' : '未完成');
  let estimateLabel = $derived(`${Math.ceil(task.estimateMinutes / 15) * 15}分钟块`);
</script>

<article class:done={task.done} class="task-card">
  <div>
    <p class="status">{statusLabel}</p>
    <h3>{task.title}</h3>
    <p>{estimateLabel}</p>
  </div>

  <ul aria-label="标签">
    {#each task.tags as tag}
      <li>{tag}</li>
    {/each}
  </ul>

  <button type="button" aria-pressed={task.done} onclick={() => onToggle(task.id)}>
    {task.done ? '标为未完成' : '标为完成'}
  </button>
</article>

<style>
  .task-card {
    display: grid;
    gap: 0.75rem;
    border: 1px solid #ddd;
    border-radius: 0.5rem;
    padding: 1rem;
  }

  .done {
    background: #f2fff5;
  }

  .status {
    font-size: 0.875rem;
    font-weight: 700;
  }

  ul {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    list-style: none;
    padding: 0;
  }

  li {
    border-radius: 999px;
    background: #eef2ff;
    padding: 0.2rem 0.6rem;
  }
</style>

给Claude Code的请求要保护组件契约:

请改进src/lib/components/TaskCard.svelte,但保持Svelte 5 runes写法。
要求:
- 不改变Task类型和onToggle签名
- 保留onclick,不要改回旧式on:click
- 保留按钮的aria-pressed
- 只改布局和空数据表现
- 修改后给出一个组件测试建议

这样写的好处是,Claude Code不会顺手把父组件、类型和路由都改掉。Svelte组件越小,AI修改越可控。

共享状态:优先runes,必要时再用stores

Svelte 5允许在 .svelte.ts 文件里使用runes。官方文档说明,这类文件适合复用响应式逻辑或在应用中共享状态。svelte/store 仍然有价值,尤其是复杂异步流、手动订阅、或与已有store生态集成时。

// src/lib/state/taskFilters.svelte.ts
export type TaskStatus = 'all' | 'open' | 'done';

export const taskFilters = $state({
  query: '',
  status: 'all' as TaskStatus,
  tag: ''
});

export function resetTaskFilters() {
  taskFilters.query = '';
  taskFilters.status = 'all';
  taskFilters.tag = '';
}
<!-- src/lib/components/TaskFilterPanel.svelte -->
<script lang="ts">
  import { resetTaskFilters, taskFilters } from '$lib/state/taskFilters.svelte';
</script>

<section aria-label="任务筛选">
  <label>
    关键词
    <input bind:value={taskFilters.query} placeholder="发票、文章、评审..." />
  </label>

  <label>
    状态
    <select bind:value={taskFilters.status}>
      <option value="all">全部</option>
      <option value="open">未完成</option>
      <option value="done">已完成</option>
    </select>
  </label>

  <button type="button" onclick={resetTaskFilters}>重置</button>
</section>

常见错误是忘记SSR。windowdocumentlocalStorage 只在浏览器存在,不能在服务端渲染阶段直接使用。需要浏览器保存时,用 $app/environmentbrowser 判断。

// src/lib/state/theme.svelte.ts
import { browser } from '$app/environment';

export const themeState = $state({
  theme: 'system' as 'system' | 'light' | 'dark'
});

export function loadTheme() {
  if (!browser) return;
  const saved = localStorage.getItem('theme');
  if (saved === 'light' || saved === 'dark' || saved === 'system') {
    themeState.theme = saved;
  }
}

export function saveTheme(nextTheme: typeof themeState.theme) {
  themeState.theme = nextTheme;
  if (browser) localStorage.setItem('theme', nextTheme);
}

路由、load函数和server边界

SvelteKit的核心是文件路由。src/routes/about 对应 /aboutsrc/routes/tasks/[slug] 对应带 slug 参数的详情页。页面显示前需要数据时,可以在同级目录放 +page.server.ts。数据库、私有API、环境变量等只应该放在 $lib/server 或server-only文件中。

// src/lib/server/tasks.ts
export type Task = {
  id: string;
  slug: string;
  title: string;
  done: boolean;
  estimateMinutes: number;
  tags: string[];
};

const tasks: Task[] = [
  {
    id: 'task-1',
    slug: 'write-svelte-guide',
    title: '起草SvelteKit文章',
    done: false,
    estimateMinutes: 45,
    tags: ['writing', 'svelte']
  }
];

export async function getTaskBySlug(slug: string) {
  return tasks.find((task) => task.slug === slug) ?? null;
}
// src/routes/tasks/[slug]/+page.server.ts
import { error } from '@sveltejs/kit';
import type { PageServerLoad } from './$types';
import { getTaskBySlug } from '$lib/server/tasks';

export const load: PageServerLoad = async ({ params }) => {
  const task = await getTaskBySlug(params.slug);

  if (!task) {
    error(404, 'Task not found');
  }

  return { task };
};
<!-- src/routes/tasks/[slug]/+page.svelte -->
<script lang="ts">
  import type { PageProps } from './$types';

  let { data }: PageProps = $props();
</script>

<svelte:head>
  <title>{data.task.title} | Tasks</title>
</svelte:head>

<article>
  <p>{data.task.done ? '已完成' : '未完成'}</p>
  <h1>{data.task.title}</h1>
  <p>预计: {data.task.estimateMinutes}分钟</p>
</article>

给Claude Code的安全提示词可以这样写:

请读取src/routes/tasks/[slug]和src/lib/server/tasks.ts。
给Task增加dueDate字段,并在详情页显示。
服务端数据访问必须留在$lib/server。
不要重命名[slug]路由目录。
最后运行npm run check。

表单actions与渐进增强

SvelteKit form actions允许 +page.server.ts 导出 actions,普通 <form method="POST"> 就能提交到服务端。JavaScript不可用时也能工作;有JavaScript时再用 use:enhance 改善体验。这对咨询表单、注册表单、内部审批表单都很实用。

// src/routes/contact/+page.server.ts
import { fail } from '@sveltejs/kit';
import type { Actions } from './$types';

export const actions = {
  default: async ({ request }) => {
    const formData = await request.formData();
    const values = {
      name: String(formData.get('name') ?? '').trim(),
      email: String(formData.get('email') ?? '').trim(),
      message: String(formData.get('message') ?? '').trim()
    };

    const errors: Record<string, string> = {};
    if (values.name.length < 2) errors.name = '姓名至少需要2个字符。';
    if (!values.email.includes('@')) errors.email = '请确认邮箱地址。';
    if (values.message.length < 10) errors.message = '内容至少需要10个字符。';

    if (Object.keys(errors).length > 0) {
      return fail(400, { values, errors });
    }

    console.log('New inquiry', values);
    return { success: true };
  }
} satisfies Actions;
<!-- src/routes/contact/+page.svelte -->
<script lang="ts">
  import { enhance } from '$app/forms';
  import type { PageProps } from './$types';

  let { form }: PageProps = $props();
</script>

{#if form?.success}
  <p role="status">已发送。我们会在1到3个工作日内回复。</p>
{/if}

<form method="POST" use:enhance>
  <label>
    姓名
    <input name="name" value={form?.values?.name ?? ''} aria-invalid={!!form?.errors?.name} />
  </label>
  {#if form?.errors?.name}<p>{form.errors.name}</p>{/if}

  <label>
    邮箱
    <input name="email" type="email" value={form?.values?.email ?? ''} aria-invalid={!!form?.errors?.email} />
  </label>
  {#if form?.errors?.email}<p>{form.errors.email}</p>{/if}

  <label>
    内容
    <textarea name="message" rows="5" aria-invalid={!!form?.errors?.message}>{form?.values?.message ?? ''}</textarea>
  </label>
  {#if form?.errors?.message}<p>{form.errors.message}</p>{/if}

  <button type="submit">发送</button>
</form>

不要用 GET 产生副作用,不要把私钥传给浏览器,不要用 {@html} 直接显示未清洗内容。让Claude Code改表单时,明确写上“保留服务端验证”“无JavaScript也能提交”“保留可访问性属性”。

测试、用例和常见坑

Svelte官方测试文档提到,Vite和SvelteKit项目很适合使用Vitest。组件测试可以用Testing Library,端到端流程再交给Playwright。

// src/lib/components/TaskCard.test.ts
import { fireEvent, render, screen } from '@testing-library/svelte';
import { describe, expect, it } from 'vitest';
import TaskCard from './TaskCard.svelte';

describe('TaskCard', () => {
  it('toggles the task when the button is clicked', async () => {
    let toggledId = '';

    render(TaskCard, {
      task: {
        id: 'task-1',
        title: '写SvelteKit文章',
        done: false,
        estimateMinutes: 45,
        tags: ['writing']
      },
      onToggle: (id) => {
        toggledId = id;
      }
    });

    await fireEvent.click(screen.getByRole('button', { name: '标为完成' }));
    expect(toggledId).toBe('task-1');
  });
});
npm run check
npm run test
npm run build
git diff -- src/lib src/routes
使用场景适合交给Claude Code人类必须检查
后台筛选UI$state$derived 拆分筛选逻辑哪些条件进入URL,哪些字段受权限控制
博客/CMS详情页连接 [slug]load、SEO标题和404HTML清洗、草稿可见性、预览规则
咨询或获客表单actions、验证、use:enhance、测试隐私、通知目标、反垃圾策略
Svelte 4迁移Svelte 5小范围把 export let$: 改成runes不要自动大迁移导致行为变化

最常见的坑有五个。第一,需求太大,导致Claude Code同时改路由、UI、数据库和认证。第二,Svelte 4和Svelte 5写法混在一起。第三,从组件中导入 $lib/server 泄露server-only边界。第四,把 $effect 用来做普通计算,产生难追踪循环。第五,只接受“按钮存在”这种弱测试,没有验证点击、错误提示、成功状态和404。

如果你希望把SvelteKit文章、表单和咨询转成收入线索,可以把技术内容自然连接到 Claude Code咨询页面。继续学习时,也建议阅读 Claude Code入门指南TypeScript技巧测试策略

参考资料、提示词模板和实际结果

需要确认行为时,请优先看官方资料:Svelte文档SvelteKit文档SvelteKit form actionsVite指南Claude Code文档

请先读取当前SvelteKit结构,然后只改下面范围。
文件: src/routes/contact/+page.svelte 和 src/routes/contact/+page.server.ts
目标: 给咨询表单增加company字段
约束:
- 保持Svelte 5 runes写法
- 不删除use:enhance
- 增加服务端验证
- 不改现有CTA文案和布局class
- 完成前运行npm run check
最后用3行总结: 改动、风险、还缺的测试。

Masa在一个小型SvelteKit任务应用中试过这套流程后,最明显的收益来自plan mode。先让Claude Code读结构,再限定“保留runes语法、运行 npm run check、不要commit”,最终diff更小,初学者也更容易审查每一处Svelte和SvelteKit改动。

#Claude Code #Svelte #SvelteKit #frontend #TypeScript
免费

免费 PDF: Claude Code 速查表

输入邮箱即可获取一页 PDF,整理常用命令、审查习惯和安全工作流。

我们会妥善保护你的信息,不发送垃圾邮件。

把 Claude Code 变成真正能带来结果的工作流

先领取中文说明的免费 PDF,再进入英文商品页选择合适的教材。如果你需要团队落地、流程设计或内容变现支持,也可以直接咨询。

Masa

关于作者

Masa

专注 Claude Code 实务流程、团队导入和内容转化的工程师。