关于 svelte5
svelte5 是面向 Svelte 5 组件编写与审查的技能,适用于开发者。它以状态所有权、可见的数据流和语义化标记为核心,帮助识别旧语法与常见反模式。
主要功能
- 01Svelte 5 响应式设计原则
- 02组件状态与属性建模
- 03组件 API 与 HTML 语义审查
- 04代码异味检查与重写建议
- 05区分 Svelte 4 与 Svelte 5 项目
适用场景
- 01审查 Svelte 5 组件的数据流
- 02将副作用改为派生状态或事件处理
- 03检查无障碍与 SSR 状态风险
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ joshuadavidthomas/ agent-skills --skill svelte5安装后在 Claude Code 中输入/svelte5确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
README.mdreferences/actions-vs-components.mdactions.mdattachments.mdbindable-by-default.mdbindings-and-directives.mdclass-state-common-mistakes.mdclass-state-patterns.mdclass-state-ssr-safety.mdcomponent-patterns.mdcontext-identity.mdcontext-vs-scoped-state.mddebugging.mddeep-state-without-immutable-ceremony.mdeffect-driven-state.mdimperative-api.mdprop-mirroring.mdread-tracked-reactivity.mdrunes-common-mistakes.mdrunes-component-api.mdrunes-reactivity-patterns.mdsemantic-html-first.mdshadcn-svelte-forms.mdsnippets-as-render-functions.mdsnippets-vs-slots.mdspecial-elements.mdssr-state-leaks.mdstate-ownership.mdstatic-runes.mdstores.md详细介绍
Think in Svelte 5
你已经熟悉 Svelte 语法。这项技能会改变你的默认选择——设计组件、放置状态、建模响应性以及审查 UI 代码时,你会优先采用什么做法。
核心问题在于:Svelte 代码虽然能编译,但思路却像 React、Vue 或 Svelte 4——用 effect 代替派生值和事件,把 props 镜像到状态中,习惯性使用全局 store,默认双向绑定,使用可点击的 div,在新代码中使用 Svelte 4 组件 API。
组件是一个依赖关系清晰可见的小型响应式程序。保持数据流直接、状态归属明确、标记语义化;让编译器和 DOM 完成它们的工作。
这项技能是审查 Svelte 组件的通用入口;对于 SvelteKit 层面的关注事项,也请使用 sveltekit(参见交叉引用)。
将这些原则视为强默认做法,而非死板的规则:不确定时,选择能更明确地表达归属、依赖关系和用户语义的做法。
Svelte 的思维方式
让响应性一目了然
1. 响应性通过读取进行追踪。 $derived/$effect 会依赖其运行期间读取的内容;如果它意外重新运行,请检查它读取了什么,而不是依赖数组。参见 references/read-tracked-reactivity.md。
2. 派生状态用 $derived,而不是 $effect。 其他状态的纯函数结果应使用派生值;effect 用于副作用,而不是让变量保持同步。参见 references/effect-driven-state.md。
let doubled = $state(0);
$effect(() => { doubled = count * 2; });
let doubled = $derived(count * 2);
3. Effects 是逃生舱。 使用 $effect 前,先确认是否可以用派生值、事件处理器或 bind: getter/setter。只有在需要操作外部环境时才使用它——例如订阅、计时器、观察器、命令式 API、日志记录——并返回清理函数。
4. Runes 可静态分析。 它们是编译器语法,而不是运行时 hook——可复用状态应使用 .svelte.ts 类和工厂函数,而不是自定义 hook。参见 references/static-runes.md。
5. $state 是深层代理,不是 React 状态。 在局部数组和对象中直接修改变更的内容;无需遵循不可变更新的繁琐流程。参见 references/deep-state-without-immutable-ceremony.md。
将状态放在归属最明确的位置
6. 状态有所属。 局部交互状态 → 组件;可复用行为 → .svelte.ts 类;在后代间共享 → context;只有需要 store 契约时才用 store,而不是把每个变化的值都放进去。参见 references/state-ownership.md。
7. 除非你确实需要“草稿”,否则不要镜像 props。 将 props 复制到 $state 会产生两个事实来源——应从 props 派生,或者创建一个命名明确、可重置和提交的可编辑草稿。参见 references/prop-mirroring.md。
let { value } = $props();
let local = $state(value); // stale if parent changes
let { value } = $props();
let display = $derived(value.toUpperCase());
8. Context 共享的是身份,而不是提供者重新渲染。 将响应式对象/类放入 context,并修改其属性;替换普通值的行为不会像 React Provider 更新那样生效。参见 references/context-identity.md。
9. 在 SSR 应用中,模块级可变状态值得警惕。 在 SvelteKit 中,导出的可变实例会在请求之间泄漏——请使用工厂函数、context 或归属于请求的数据。参见 references/ssr-state-leaks.md。
围绕所有权设计组件 API
10. Props 描述输入;回调描述事件。 组件事件是回调 props;除非要保留旧的公共 API,否则新代码中应避免使用 createEventDispatcher。参见 references/component-patterns.md。
const dispatch = createEventDispatcher();
function handleClick() { dispatch('select', item); }
let { onSelect } = $props();
function handleClick() { onSelect?.(item); }
11. 双向绑定是一项 API 承诺。 $bindable 表示子组件可以修改由父组件拥有的状态——将其用于表单控件和有意设计为受控组件的场景,而不要将其作为默认做法。参见 references/bindable-by-default.md。
12. Snippet 是渲染函数,而不是改了名字的 slot。 当父组件提供 UI 时使用它们;为其参数添加类型,并按职责命名。参见 references/snippets-as-render-functions.md。
13. 包装组件应保留平台能力。 包装 button 意味着接受 button 属性,并保留 type、disabled、焦点和 ARIA。参见 references/wrapper-components-preserve-html.md。
让 HTML 和编译器发挥作用
14. 优先使用原生元素,再添加自定义行为。 button 已能处理键盘、焦点、禁用状态和无障碍功能;可点击的 div 则会拙劣地重造平台能力。参见 references/semantic-html-first.md。
15. 设计系统字段应保留表单语义。 在 shadcn-svelte 或 bits-ui 表单中,使用 Field.* 实现标签、分组、描述和错误信息——不要使用原始 div、单独导入 Label,也不要使用可点击的选项行。参见 references/shadcn-svelte-forms.md。
16. 组件负责标记;actions/attachments 负责 DOM 行为。 渲染 UI → component。将可复用的命令式行为附加到元素 → action 或 attachment。参见 references/actions-vs-components.md。
17. Svelte 5 语法应保持一致。 新代码使用 $props、onclick 风格的属性、snippets 和回调 props;除维护旧代码外,不要混用旧语法。参见 references/svelte5-syntax-discipline.md。
18. 为边界添加类型,而不是事无巨细地添加类型。 非简单组件应定义 Props 类型;为 snippets 和回调添加类型;包装组件使用 svelte/elements;避免在边界使用宽泛的 any。参见 references/typescript.md。
运行审查
- 先检测版本。 查看
package.json中的svelte主版本,并检查svelte.config.*。在 Svelte 5 项目中,标记 Svelte 4 模式(export let、on:event、<slot>、createEventDispatcher);在 Svelte 4 项目中,除非任务是迁移,否则不要建议使用仅适用于 Svelte 5 的语法。 - 应用上述原则;扫描下方的异味索引。 提出重写方案前,先打开链接的参考资料。
- 仅凭证据或明显的规模判断性能。 为已识别的
{#each}添加 key,将繁重的工作从标记中移至$derived,避免不必要的双向绑定。大多数代码无需手动优化。 - 组织输出: 先列出影响最大的事项(正确性、响应性、无障碍、SSR 泄漏),再给出建议的重写方案(以最小的有效改动为准),最后列出可选的改进。每一点都应关联到行为、可维护性或用户影响——不要纠缠于每个风格小问题。
代码异味索引
查找异味;上面的原则提供了修复方法。
| 代码异味 | 参考 |
|---|---|
| 新代码中使用旧版 Svelte 语法 | svelte5-syntax-discipline |
| Effect 赋值给派生值 | effect-driven-state |
| Effect 响应控件变化 | effect-driven-state |
| Effect 转换绑定值 | bindings-and-directives |
| Effect 神秘地重新运行 | read-tracked-reactivity |
| 在辅助函数或 hook 中调用 Rune | static-runes |
| 对本地状态进行繁琐的不可变更新 | deep-state-without-immutable-ceremony |
| 将 Prop 复制到本地状态 | prop-mirroring |
| 默认使用全局 store/所有权不明确 | state-ownership |
| 替换 Context 值而非修改它 | context-identity |
| 在 SvelteKit 中导出可变单例 | ssr-state-leaks |
使用 createEventDispatcher 发出事件 | component-patterns |
习惯性使用 $bindable | bindable-by-default |
类似 Slot 的 API(export let、<slot>) | snippets-as-render-functions |
可点击的 div/span | semantic-html-first |
| 用原始包装组件重建 shadcn-svelte 表单 | shadcn-svelte-forms |
| 隐藏原生行为的包装组件 | wrapper-components-preserve-html |
| 由 Action 管理标记/状态 | actions-vs-components |
| 动态列表未使用 key | bindings-and-directives |
组件边界处使用宽泛的 any | typescript |
{@html} 包含用户内容 | template-tags |
| 组件行为未经测试 | testing |
交叉引用
- sveltekit — 路由、布局、
load、表单操作、远程函数、Cookie、身份验证、端点、重定向、服务器错误、应用级 SSR/数据流