要点
本篇是 Svelte 5 与 SvelteKit 2 的条目式速查,按用途分六组:响应式符文、模板语法、组件与生命周期、SvelteKit 路由文件、SvelteKit 模块、配置与工程;文末有全量速查表,可只搜表定位条目。版本基线为 Svelte 5.43.x 与 SvelteKit 2.48.x(截至 2025-11-03 的稳定线),仅在此基线成立的特性单独标注版本。路由与 load 的完整讲解不在本篇重复,见SvelteKit 路由与数据加载:load 函数详解;框架定位与选型判断见开山篇Svelte 入门。
响应式符文组
符文(runes)是编译期标记而非运行时函数,写给编译器看。全量如下:
| 符文 | 一句话用途 | 有什么坑 |
|---|---|---|
| $state(v) | 声明响应式状态 | 对象与数组是深层代理,直接 console.log 全是 Proxy;要看原始值用 $state.snapshot |
| $derived(expr) | 派生值,依赖变化自动重算 | 派生值只读,在别处赋值是编译错误;多行逻辑用 $derived.by(() => {…}) |
| $effect(fn) | 副作用,依赖的信号变化时重跑 | 返回的函数作清理;不要在里面写能算出来的状态,那该用 $derived |
| $effect.pre(fn) | DOM 更新前执行的副作用 | 测量布局(读滚动位置等)用它,$effect 里读是更新后的旧值 |
| $props() | 解构声明组件入参 | 带默认值写 let { size = 24 } = $props();剩余属性用 rest 解构 |
| $bindable(v) | 标记允许双向绑定的入参 | 只包 $props 里解构出的属性;未标记的 prop 上 bind: 是编译错误 |
| $inspect(v) | 开发期打印值变化 | 生产构建中被剔除,别拿它当日志系统 |
| $host() | 自定义元素内部取宿主 | 仅 custom elements 场景 |
$state:响应式从声明开始
let count = $state(0);
let list = $state(['a', 'b']);
list.push('c'); // 数组方法直接用,深层代理会自动触发更新
console.log($state.snapshot(list)); // ['a', 'b', 'c'] —— 排查时的原始值
一句话语义:声明”这个值变了,用它的地方要更新”。类字段同样可写 count = $state(0)。
⚠️ 常见坑:从 Svelte 4 教程带过来的习惯——解构 props 或重组件入参后丢失响应性。let { items } = $props() 拿到的 items 若被子组件用 $state 重建,父层引用不会跟着换;要保持追踪,解构后直接用,别再赋值给普通变量。
$derived:能算出来的不要存
let query = $state('');
let hits = $derived.by(() => {
const q = query.trim().toLowerCase();
return q ? all.filter(x => x.title.toLowerCase().includes(q)) : all;
});
一句话语义:声明”这个值由别的值算出”,无需手写依赖列表。
⚠️ 常见坑:把派生写成 $effect 加赋值——多一轮更新循环,依赖关系被藏进副作用,是官方文档点名的头号误用;判断标准就一条:能从别的值算出来,就用 $derived。
$effect:只留给”外部世界”
$effect(() => {
document.title = `购物车 ${items.length} 件`; // 触碰 Svelte 管辖之外的 DOM
return () => console.log('清理'); // 可选清理函数
});
⚠️ 常见坑:在 $effect 里发请求”补数据”来替代 load——SSR 首屏没有这份请求,白做一次服务端渲染;数据该走 SvelteKit 的 load(见路由篇),$effect 留给打点、标题、非 Svelte 组件的桥接。
模板语法组
| 语法 | 一句话用途 | 有什么坑 |
|---|---|---|
| {#if} / {:else if} / {:else} / {/if} | 条件渲染 | 无三元之外的表达式限制,常规 JS 表达式均可 |
| {#each list as item (item.id)} | 列表渲染,括号里是 key | 不写 key 是”就地复用”,列表重排时输入框状态会串行;能定唯一 id 就写 key |
| {#await p} {:then v} {:catch e} | Promise 三态渲染 | 服务端 load 返回的流式 Promise 用它接,见路由篇 |
| {#key expr} | 表达式变化时销毁重建内部块 | 重置组件状态的手段,滥用会丢性能与状态 |
| {#snippet name(a)} / {@render name(a)} | 定义与渲染可复用模板块(替代旧 slot) | 声明即值,可作为 props 传给子组件;旧 slot 语法仍兼容但已让位 |
| {@html str} | 插入原始 HTML | 不消毒,内容含用户输入就是存储型 XSS;必须先白名单消毒 |
| {onclick={() => …}} | 事件属性(Svelte 5 写法) | 旧 on:click 指令已弃用;修饰符 |preventDefault 一并取消,需手动 e.preventDefault() |
| bind:value / bind:group / bind:this | 双向绑定与元素引用 | bind:this 绑的是元素实例,在挂载前读是 undefined |
| class:active={cond} | 条件 class 指令 | 5.16 起 class 属性直接支持对象/数组写法,批量场景更清爽 |
| use:action | 元素级扩展(action) | 返回 { update, destroy };参数变化走 update,不是重建节点 |
| transition:fade / in: / out: | 进出场过渡 | 本地过渡默认不随全局状态播放,需 |global 修饰才跨块生效 |
| animate:flip | keyed each 重排动画 | 只对带 key 的 each 直接子元素生效,套一层 div 就失灵 |
| 错误边界(5.3+) | failed snippet 兜底 UI,onerror 收错误对象;SSR 期间不捕获 | |
| {@attach fn} | attachments(5.29+) | 比 action 更贴近元素生命周期;新代码二选一即可,不必迁移存量 action |
⚠️ 常见坑(本组最贵的一个):{@html} 直出用户输入。哪怕内容来自”自家编辑器”,也要在服务端用白名单消毒后再入库或直出——Svelte 不替你消毒,这行语法是全 Svelte 应用里最常见的 XSS 入口。
组件与生命周期组
| API | 一句话用途 | 有什么坑 |
|---|---|---|
| mount(App, { target, props }) | 客户端挂载组件(Svelte 5 入口) | 替代 new Component();返回实例传给 unmount |
| hydrate(App, { target }) | 在 SSR 产物上激活 | 与服务端渲染结果不一致会告警并整块重渲 |
| unmount(app) | 卸载组件并跑清理 | Svelte 5 返回 Promise 形态的清理句柄 |
| tick() | 等本轮 DOM 更新落定 | 改完状态立刻量 DOM 要先 await tick() |
| flushSync(fn) | 强制同步刷新更新 | 与第三方库桥接时用,普通业务代码不需要 |
| untrack(fn) | 读信号但不建立依赖 | 在 $effect 里读”只想要当前值”的大对象时用它防误触发 |
| createEventDispatcher | (已弃用)组件事件 | Svelte 5 用回调 props(onXxx)替代,新代码不要再写 |
SvelteKit 路由文件组
文件树即路由表,各特殊文件的分工速查如下(优先级、动态段写法与 load 重跑规则的完整版见路由篇):
| 文件 | 一句话用途 | 有什么坑 |
|---|---|---|
| +page.svelte | 页面 UI | 数据从 let { data } = $props() 进来 |
| +page.js | universal load | 跑在客户端,密钥和私密导入进来就泄漏 |
| +page.server.js | server load 与 actions | 仅服务端;返回值必须可序列化(devalue) |
| +layout.svelte | 嵌套布局,{@render children()} | 布局实例跨子路由导航保留,状态不会自动重置 |
| +layout.js / .server.js | 子树共享数据 / 页面选项(prerender、ssr、csr) | 写在 layout 上对整棵子树生效 |
| +server.js | API 端点(GET/POST…) | 返回 Response 对象;与 +page.svelte 同目录时按 Accept 分流 |
| +error.svelte | 层级错误兜底 | 就近接管;根部那个兜住全部 |
| hooks.server.js | handle:每个请求的入口拦截 | 必须调 resolve(event) 返回响应,忘了整站无响应 |
SvelteKit 模块组
| 模块 / 导出 | 一句话用途 | 有什么坑 |
|---|---|---|
| $app/state: page | 当前页的 url/params/data/status/form/error(2.12+) | 是响应式对象不是 store:读 page.data,不写 $page.data |
| $app/state: navigating / updated | 导航进行中信息 / 部署更新检测 | $app/stores 是它的前身,已弃用但仍可用 |
| $app/navigation: goto | 编程式导航 | 默认不强制刷新数据,同 URL 用 invalidate |
| $app/navigation: invalidate / invalidateAll | 手动触发 load 重跑 | 只对”读过该依赖”的 load 生效,见路由篇 |
| $app/navigation: prefetch / preloadData | 悬停预取 / 提前跑 load | data-sveltekit-preloaddata 属性可声明式开启 |
| $app/forms: enhance | use:enhance 渐进增强表单 | 自定义回调时记得调默认行为 update(),否则 action 结果不回填 |
| $app/forms: applyAction / deserialize | 手动消费 action 结果 | 自造提交逻辑时用,别自己 fetch action URL |
| $app/paths: base / assets | 部署路径前缀 | 手拼 URL 忘加 base,非根路径部署时资源全 404 |
| $app/environment: browser / dev / building | 运行环境判断 | 替代”typeof window !== ‘undefined'”式判断 |
| $env/static/private | 构建期内联的私密变量 | 只能进 server load/actions/hooks;被 universal load 或组件 import 直接报错 |
| $env/static/public | 构建期内联的公开变量 | 会打进客户端产物,放敏感值就等于公开 |
| $env/dynamic/private|public | 运行时读取的环境变量 | private 版只能在服务端用;值不内联,改环境不用重建 |
| @sveltejs/kit: error(status, msg) | 抛出带状态的请求错误 | SvelteKit 2 改为抛出式;用 throw 或直接调用皆可 |
| @sveltejs/kit: redirect(status, url) | 抛出重定向 | 不能放在 try 块里——catch 会把它吞掉 |
| @sveltejs/kit: fail(status, data) | action 返回校验错误 | 4xx 校验错误用 fail 而不是 error:前者回填表单,后者进错误页 |
| @sveltejs/kit: json / text | 构造 Response 的便捷函数 | +server.js 里返回 Response 也可以,函数只是省事 |
hooks 的两个文件级导出单独说一句:handle 是每个请求的必经之路(挂 event.locals、鉴权、日志都在这),多个中间件用 sequence()(来自 @sveltejs/kit/hooks)串联;handleError 只处理未捕获异常,不能用它改变响应内容。
配置与工程组
| 条目 | 一句话用途 | 有什么坑 |
|---|---|---|
| npx sv create [path] | 官方脚手架(sv CLI,本文时点 0.9.x) | –template minimal/demo/library/addon、–types ts/jsdoc、–no-add-ons、–install npm/pnpm/yarn/bun/deno |
| sv add | 给项目加生态件(eslint、prettier、tailwindcss、vitest、playwright 等) | 清单随版本变,以 sv add –help 为准 |
| sv check | 类型与模板检查(svelte-check 封装) | 放 CI 跑,别靠编辑器插件兜底 |
| sv migrate | 官方迁移脚本(如 Svelte 4 组件迁移到 5) | 机械转换覆盖不到全部,跑完必须人工过一遍 |
| svelte.config.js: kit.adapter | 部署目标适配器 | adapter-auto 在未知平台回落 node 可跑但告警,自建服务器显式用 adapter-node |
| adapter-static | 纯静态导出 | 全站必须可 prerender,用了一个 server load 就打不出包 |
| kit.csrf.origin 检查 | POST 按请求头 Origin 校验 | curl 直接 POST action 会被 403,测试要带 Origin 头 |
| compilerOptions.experimental.async | 实验性 async SSR(Svelte 5.39.3+ / Kit 2.43+) | 截至本文仍是实验特性,生产以官方文档为准 |
全量速查表
| 条目 | 一句话用途 | 有什么坑 |
|---|---|---|
| $state | 响应式状态 | 深层代理,看原始值用 snapshot |
| $derived / $derived.by | 派生值 | 能算出来的别用 effect 存 |
| $effect / $effect.pre | 副作用 / DOM 更新前 | 只留给外部世界;量布局用 pre |
| $props / $bindable | 入参 / 可双向入参 | 未标记的 prop 不能 bind: |
| {#each (key)} | 带 key 列表渲染 | 重排列表必须写 key |
| {@html} | 原始 HTML | 不消毒就是 XSS |
| onclick 事件属性 | Svelte 5 事件写法 | on: 指令与修饰符已弃用 |
| bind:value / bind:this | 双向绑定 / 引用 | bind:this 挂载前是 undefined |
| use:action / {@attach} | 元素扩展(action / 5.29+ attachment) | 参数变化走 update 不重建 |
| 错误边界(5.3+) | SSR 期间不捕获 | |
| mount / hydrate / unmount | 组件挂载三件套 | 替代 new Component() |
| +page.js vs +page.server.js | universal vs server load | universal 里别碰密钥 |
| event.fetch | load 内请求 | 全局 fetch 丢凭证、无相对路径 |
| invalidate / invalidateAll | 手动重跑 load | server load 不随查询串重跑 |
| $app/state: page | 页面状态(2.12+) | 响应式对象,非 store |
| goto / prefetch | 导航与预取 | 同 URL 要数据刷新用 invalidate |
| use:enhance | 表单渐进增强 | 自定义回调别丢了默认 update() |
| $env/static/* | 构建期内联环境变量 | private 进不了客户端,public 全公开 |
| error / redirect / fail | 错误 / 重定向 / action 校验失败 | redirect 别放 try 里;校验错误用 fail |
| adapter-node / adapter-static | 自托管 / 纯静态 | static 要求全站可 prerender |
延伸阅读
路由与 load 的机制讲解见SvelteKit 路由与数据加载;把这些 API 组合起来做一个完整应用的过程见实战篇用 SvelteKit 做一个 Markdown 片段收藏夹(2025-11-06 发布);按阶段串起本站相关文章的路径见Svelte 学习路线(2025-11-13 发布);模块与 ESM 基础不熟的,先补站内Node.js 模块与 ESM。
版本核实(以官方文档为准):截至本文(2025-11-03)稳定线为 Svelte 5.43.x、SvelteKit 2.48.x;$app/state 自 SvelteKit 2.12(2024-12)提供并取代 $app/stores;svelte:boundary 自 Svelte 5.3(2024-12);class 属性对象/数组写法自 5.16(2024-12);attachments 自 5.29(2025-05);remote functions 自 SvelteKit 2.27(2025-07)起为实验特性;实验性 async SSR 需 Svelte 5.39.3+ 与 SvelteKit 2.43+。安装命令不钉版本号,API 细节以 svelte.dev 当前文档为准。