关于 svelte
面向特定项目的 Svelte 5 开发指南,涵盖组件、响应式、生命周期和 UI 组合,适用于该工作区的开发者,并强调对关键行为变更核查上游资料。
主要功能
- 01Svelte 5 runes 与响应式指南
- 02组件属性、片段和事件模式
- 03生命周期与异步资源模式
- 04响应式集合和存储集成指南
- 05TanStack Query mutation 约定
- 06上游源码核验指南
适用场景
- 01实现或更新 Svelte 组件
- 02选择状态和生命周期模式
- 03将工作区数据接入响应式 UI
- 04核实影响行为的 Svelte API 变更
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ epicenterhq/ epicenter --skill svelte安装后在 Claude Code 中输入/svelte确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/component-ui-patterns.mdinput-ownership.mdlifecycle-and-reactivity.mdmutations-and-workspace-inputs.md详细介绍
Svelte 指南
首轮重点关注 Svelte 符文、组件生命周期、由工作区支持的状态、TanStack Query 用法和本地 UI 组合。
参考仓库
- Svelte:采用符文和细粒度响应性的 Svelte 5 框架
- shadcn-svelte:为 Svelte 移植的 shadcn/ui,使用 Bits UI 基元
- shadcn-svelte-extras:shadcn-svelte 的附加组件
源码检查
- 更改属性所有权、
bind:API 或children片段的类型规则前,请检查 Svelte$props、$bindable和片段。 - 更改带键资源或异步就绪状态的指南前,请检查 Svelte
{#key}、{#await}和生命周期钩子。 - 更改可复用 DOM 行为、操作或附加项指南前,请检查 Svelte
{@attach}、use:和svelte/attachments。 - 更改
SvelteMap、SvelteSet或响应式集合指南前,请检查 Sveltesvelte/reactivity。 - 更改避免使用旧版 API、事件语法、插槽迁移或回调属性指南前,请检查 Svelte 5 迁移指南。
- 更改变更生命周期指南前,请检查 TanStack Svelte Query
createMutation和本地已安装的类型。
上游依据
当 Svelte 5 符文、编译器行为、生命周期、响应性、片段或模板行为会影响正确性时,应先基于源码确认,不要仅凭记忆。如果 DeepWiki MCP 可用,请针对 sveltejs/svelte 提出范围明确的问题;对于 SvelteKit 集成,请针对 sveltejs/kit 提问;对于 shadcn-svelte 或 extras 组件 API,请针对 huntabyte/shadcn-svelte 或 ieedan/shadcn-svelte-extras 提问。如果 DeepWiki 不可用或仓库未建立索引,请直接使用上游源码或官方文档。将 DeepWiki 作为了解方向的起点,然后在更改代码前,根据本地已安装的类型、源码或官方文档核实关键细节。
对于稳定的基础知识以及此处或参考资料中已有文档记录的仓库本地模式,无需使用 DeepWiki。
相关技能
query-layer:TanStack Query 集成error-handling:在操作过程中传递 Results,然后在交互边界呈现结果;包括带标签的错误和$lib/reportstyling:CSS 和 Tailwind 约定,包括弹性列滚动陷阱ui-design:视觉方向,以及加载、空状态、待处理状态、工具提示和组件选择模式
Svelte 5 基准
- 对组件会原地修改的响应式值,使用
$state。对于只会整体重新赋值的值(大型数组、仅通过替换更新的持久化存储、不透明句柄),使用$state.raw:它按引用存储,不创建深层代理,不会冻结值,且仅在重新赋值时触发响应式更新。因此,原地修改属性会改变对象,但不会触发响应式更新或持久化(这不是错误,只是不具备响应式)。当深层代理带来的响应式能力用不上,且稳定的值标识很重要时(例如,值会被 JSON 序列化或按引用比较的存储),可考虑使用它。示例:packages/svelte中的createPersistedState。 - 优先使用
$derived来计算状态。将$effect视为仅限浏览器的备用手段,用于 DOM 集成、分析、订阅和外部系统。返回的清理函数会在 effect 重新运行前以及组件销毁时执行。 - Props 可能会变化。使用
$derived计算会变化的值,或在使用处直接读取 prop。仅当适配器的归属在该组件实例中固定时,才只初始化一次;响应式属性并不意味着适配器标识会变化。阅读生命周期与响应式。 - 默认将 props 视为由父组件拥有。使用回调 prop 执行操作,仅在有意提供双向 API 时使用
$bindable,例如 UI 包装器、bind:value、bind:open和bind:ref。对于受控输入,优先使用bind:value={get, set},而非成对的读写 props;参见函数绑定。 - 对于新的 Svelte 5 代码,优先使用 snippets 和
{@render},而非 slots。使用svelte中的Snippet为暴露的 snippet props 指定类型;使用Snippet<[Row]>这类元组参数。 - 在 rune 模式代码中,避免使用旧式模式:
$:声明、export let、on:click、<slot>、<svelte:component>、<svelte:self>、beforeUpdate、afterUpdate和createEventDispatcher。 - 使用事件属性和回调 props,例如
onclick={...}、onkeydown={...}和onSelect={() => ...}风格的 props。不要在新的 rune 模式代码中添加on:指令或派发组件事件。
核心决策
- 在添加内容状态之前,先选择即时编辑还是显式提交。即时控件绑定到当前编辑器,并提交完整替换内容。显式表单为每次提交维护一份草稿,最好使用通过替换更新的
$state.raw对象;普通代理式$state在其 API 边界需要纯数据时使用$state.snapshot。请求、选择和控件状态应与此选择分开处理。 - 如果一次性资源的身份取决于 prop,就让父组件通过
{#key}或{#if}管理挂载和卸载;在子组件中同步打开资源。参阅生命周期与响应性。 - 如果就绪状态由一个稳定的 promise 决定,就在模板中使用
{#await},而不是使用$state(false)标志和取消 effect。 - 让数据读取和操作在使用处一目了然:在标记中直接读取
session.current或editor.row等所有者属性,并在控件旁内联编写转发处理器;当简短的守卫能说明交互时,也应一并写出。若名称能说明大量工作或承载必要行为(包括将通知筛选到 effects),则保留该名称。参阅组件与 UI 模式和生命周期与响应性。 - 使用
satisfies Record查找表映射有限联合类型,不要使用嵌套三元表达式或$derived.by()分支。 - 对按 ID 索引、且希望
get、has、size或迭代操作能触发响应式更新的集合,使用SvelteMap。SvelteMap中的值不会进行深度代理,因此应存储响应式行对象,或在嵌套数据变化时替换值。将映射转换为稳定数组后,再通过$derived传给表格类使用方。 - 对 ID 集合使用
SvelteSet,前提是其成员关系(has、size、迭代)会在响应式或模板上下文中读取:使用add/delete直接驱动 UI,取代$state<string[]>加展开/筛选后重新赋值。一旦集合需要携带每个键的数据(时间戳、最近一次错误),就改用SvelteMap。当集合只在命令式代码中读取时(例如订阅的监听器集合),使用普通Set/Map,而非响应式类:在任何 effect 之外读取响应式包装器,只会带来开销,却没有读取者(示例:createPersistedState中的普通listeners集合)。 - 通过
@epicenter/svelte中的fromData读取 Epicenter 存储数据:它会映射已打开数据库声明的tables/kv以及persistence,让每次读取都具有响应性,并将写入传递到底层。表会作为按行 ID 索引的实时SvelteMap投影保留:对于原始存储,在首次调用fromData时初始化;之后每次提交时根据提交中列出的 ID 更新。对同一原始存储的后续调用会返回相同投影,不会遍历表或再次订阅;即使某个已声明表没有任何内容要渲染,也会在首次调用时遍历;kv和persistence则通过createSubscriber保持直读。无需拆除任何内容,也无需手动释放任何内容:投影会随文档一同销毁。读取表数据时,不要手动编写db.<table>.subscribe(listener),再将数据写入$state.raw;使用$derived对table.rows进行筛选和排序。若要读取非表数据源中的单个值,请使用fromSubscription(subscribe, read),不要手动编写createSubscriber。适配器:packages/svelte/src/from-data.svelte.ts;应用示例:apps/honeycrisp/src/routes/components/Notes.svelte。 - 对于非存储的外部事件源(
window事件、auth 存储),使用svelte/reactivity中的createSubscriber将其接入响应式系统,不要手动编写$state、$effect和监听器集合:effect 内的读取会变为响应式,且订阅会按 effect 使用情况进行引用计数(首个订阅者到来时启动,订阅者归零时清理)。示例:packages/auth/src/svelte/auth.svelte.ts。只有在同一数据源还为命令式.get()/.watch()使用方提供服务,且其生命周期无法依赖 effect 引用计数时,才保留手动监听器集合(同样参见createPersistedState)。 - 为元素创建可复用的 DOM 行为时,优先使用
{@attach}attachments,而非新增use:actions。已有代码或仅提供 actions 的库可继续使用use:。 - 在
.svelte文件中创建 TanStack Query mutations;除非某项操作值得封装成语义明确的辅助函数,否则直接从模板处理器调用mutation.mutate(...)。参阅mutations 与工作区输入。 - 关于旧版 Y.Map 值字段,请参阅mutations 与工作区输入中的失焦时提交策略。不要将该策略用于 Folder 行编辑器;它们会立即接受输入,并自行管理发布队列。
- 对于将纯文本与表达式组合的字符串属性,使用 Svelte 引号插值(
label="Loading {name}"、href="/users/{id}"),不要使用 JavaScript 模板字面量属性。非字符串值、回调、对象、布尔值,以及整个属性都是计算所得 JavaScript 表达式的情况,仍使用表达式属性。 - 对于文件编辑器视图,请遵循编辑器所有权模式:Files 打开全文,产品列表打开结构化控件,无效文件则提供明确的修复路径。按获取到的编辑器身份对详情进行键控。共享文本控件会停用已销毁的绑定;已接受的输入和保存由视图上方的所有者负责。
- 将简单的组件 props 内联编写。只有在包装组件、泛型关系、导出契约或原生 DOM 类型组合确有需要时,才使用命名的
Props。将较大的视图模式分支拆分到职责明确的子组件中。参阅组件与 UI 模式。 - 优先使用本地
@epicenter/ui加载、空状态、待处理状态和工具提示组件,不要临时编写标记。
参考索引
- 当变更涉及带键的资源、就绪状态 Promise、
$effect清理、浅层别名、值映射、SvelteMap、表格状态或.svelte.ts状态模块时,请阅读 生命周期与响应性。 - 当变更涉及 TanStack Query mutation 的放置位置、内联处理程序、异步按钮状态、直接
await或由工作区提供支持的文本输入时,请阅读 变更与工作区输入。 - 当变更涉及 shadcn-svelte 导入、
$props类型、$bindable、片段、DOM 附加项、自包含对话框、视图分支、重复标记、内联仅使用一次的辅助函数、加载或空状态、属性优先派生或模板文本注意事项时,请阅读 组件与 UI 模式。
评论
支持 Markdown