Svelte Legacy APIs Reference (Svelte 4 → Svelte 5)
本技能覆盖 Svelte 4 的 Legacy API,这些 API 在 Svelte 5 中仍可用(Legacy Mode),但推荐迁移到 Runes。本技能仅用于理解和迁移 Legacy 代码,新代码应使用 Runes。
When to use this skill
当用户需要维护 Svelte 4 项目、理解 $: reactive 语句、export let props、createEventDispatcher、Slots、或需要将 Legacy 代码迁移到 Svelte 5 Runes Mode 时使用本技能。
Critical: Reactive let declarations
在 Legacy Mode(未使用 Runes 的组件),顶层 let 声明自动成为响应式:
<script>
let count = 0; // 自动响应式
</script>
<button on:click={() => count++}>
{count}
</button>
Svelte 5 的 Runes Mode:
let count = $state(0)。
数组/对象变更注意
Legacy 响应式基于赋值,数组方法(.push()、.splice())不触发更新:
<script>
let items = [1, 2, 3];
function addItem() {
items.push(4); // ❌ 不触发更新
items = items; // ✅ 触发
// 或
items = [...items, 4]; // ✅ 触发
}
</script>
Critical: Reactive $: statements
在 Legacy Mode,$: 标签语句创建响应式语句:
<script>
let a = 1;
let b = 2;
$: sum = a + b; // 依赖 a, b
$: console.log(`sum = ${sum}`); // 依赖 sum
</script>
拓扑排序
$: 语句按依赖拓扑排序(顺序无关):
$: z = y; // z 依赖 y
$: y = x; // y 依赖 x
$: x = 5; // x 无依赖
块级语句
$: {
total = 0;
for (const item of items) total += item.value;
}
Critical: export let
Legacy Mode 中用 export let 声明 props:
<script>
export let name; // 必需 prop
export let age = 18; // 带默认值
export let items = []; // 数组默认值
</script>
Svelte 5 Runes:
let { name, age = 18 } = $props()
重新导出(API)
<script>
export function greet(name) {
alert(`Hello ${name}!`);
}
export const VERSION = '1.0';
</script>
父组件通过 bind:this 调用:
<script>
let greeter;
</script>
<Greeter bind:this={greeter} />
<button on:click={() => greeter.greet('world')}>greet</button>
prop 重命名
<script>
export { foo as bar }; // 对外叫 bar,内部叫 foo
</script>
Critical: $$props / $$restProps
$$props(获取所有传入 props)
<script>
let { foo, ...rest } = $$props;
// foo 是显式 prop,rest 是其余所有 props
</script>
Svelte 5 Runes:
let { foo, ...rest } = $props()
$$restProps(仅剩余 props)
<script>
export let required;
let { ...rest } = $$props;
</script>
<!-- required 不在 rest 中 -->
Critical: createEventDispatcher
Legacy 的事件分发机制(已被 Svelte 5 callback props 取代):
<script>
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();
function handleClick() {
dispatch('change', { value: 42 });
dispatch('complete'); // 无数据
}
</script>
<button on:click={handleClick}>发送</button>
使用事件
<Component on:change={(e) => console.log(e.detail)} />
类型化(TypeScript)
<script lang="ts">
const dispatch = createEventDispatcher<{
change: { value: number };
complete: null;
}>();
</script>
Svelte 5 推荐:直接用 callback props:
<Component => handle(detail)} />
Critical: Slots
<slot> 是 Legacy 的内容传递机制(Svelte 5 用 Snippets 替代):
默认 slot
<!-- Component.svelte -->
<div class="card">
<slot />
</div>
<!-- 使用 -->
<Component>
<p>内容</p>
</Component>
命名 slot
<!-- Component.svelte -->
<slot name="footer" />
<slot name="header" />
<!-- 使用 -->
<Component>
<p slot="header">头部</p>
<p slot="footer">尾部</p>
</Component>
Slot props(向 slot 传数据)
<!-- Component.svelte -->
<slot value={count} />
<!-- 使用 -->
<Component let:value let:onClick>
<p>{value}</p>
<button on:click={onClick}>click</button>
</Component>
注意:Svelte 5 中,default slot props 需要
let:前缀;named slots 的 slot props 不暴露给 named slots。
$$slots(检查 slot 是否存在)
<script>
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();
$: if (!$$slots.footer) {
// footer slot 未被提供
}
</script>
Critical: svelte:component / svelte:self
<svelte:component>(动态组件)
<script>
let Current = FirstComponent;
$: Current = showSecond ? SecondComponent : FirstComponent;
</script>
<svelte:component this={Current} />
Svelte 5 推荐:
<svelte:element this={Current} />
<svelte:self>(递归组件)
<script>
import { svelte:self } from 'svelte';
</script>
<svelte:self />
Critical: svelte:fragment
<!-- Component.svelte -->
<slot name="title" />
<div>
<slot name="body" />
</div>
<!-- 使用 -->
<Component>
<h1 slot="title">Title</h1>
<svelte:fragment slot="body">
<p>多元素</p>
<p>不会被包裹</p>
</svelte:fragment>
</Component>
Critical: v5 Migration Quick Reference
| Legacy (Svelte 4) | Modern (Svelte 5) |
|---|---|
let count = 0(顶层响应式) |
let count = $state(0) |
$: x = expr |
let x = $derived(expr) |
$: { if (cond) x = v } |
$effect(() => { if (cond) x = v }) |
export let prop |
let { prop } = $props() |
$$props |
let { ...rest } = $props() |
<slot /> |
{@render children()} |
createEventDispatcher |
callback props |
on:click={fn} |
onclick={fn} |
<svelte:component this={x}> |
<svelte:element this={x}> |
<svelte:self> |
import Self from './This.svelte' + <Self> |
class:cool={isCool} |
class={{ cool: isCool }} |
let:slotProp={value} |
Snippets 自动传递 |
Gotchas
- Legacy
$:基于赋值 — 数组.push()等方法不触发更新 - Slot props 行为不同 — default slot 可访问 slot props,named slots 不可以
createEventDispatcher已废弃 — Svelte 5 不推荐,新代码用 callback props$$slots是编译时注入 — 可在 script 中直接使用$:中引用<svelte:self>需要导入 —import { svelte:self } from 'svelte'
Critical: Svelte 4 Migration (Svelte 3 → Svelte 4)
如果你正在维护 Svelte 3 项目并升级到 Svelte 4,下面这些破坏性变更必须逐项核对。详细对照与自动化脚本见 examples/migration-v4.md 与 references/migration-v4-reference.md,源码基线在 /tmp/svelte-llms.txt:6182。
推荐起点:
npx svelte-migrate@latest svelte-4—— 脚本会自动处理多数条目;其余需要手动介入。
最低版本要求
{
"engines": { "node": ">=16" },
"devDependencies": {
"svelte": "^4.0.0",
"@sveltejs/kit": ">=1.20.4",
"vite-plugin-svelte": ">=2.4.1",
"svelte-loader": ">=3.1.8",
"rollup-plugin-svelte": ">=7.1.5",
"typescript": ">=5"
}
}
主要破坏性变更速查
| 类别 | Svelte 3 | Svelte 4 |
|---|---|---|
| Bundler browser condition | 可选 | Rollup browser: true / Webpack conditionNames: ['browser'] |
| CJS 输出 | 支持 | 移除(编译器、svelte/register、runtime) |
createEventDispatcher 类型 |
可选 payload | 严格:T | undefined 可选;T 必填;null 禁 detail |
Action / ActionReturn |
params 隐式 any |
必须显式 Action<HTMLElement, T> |
onMount 异步清理 |
不报错 | 返回 Promise 的清理函数会被忽略(TS 报错) |
| Custom Element | <svelte:options tag="x" /> |
<svelte:options customElement="x" />(字符串或对象) |
SvelteComponentTyped |
与 SvelteComponent 并存 |
弃用,统一为 SvelteComponent |
| Transitions 默认范围 | 任意祖先块触发 | 仅直接父块触发,加 |global 恢复旧行为 |
| Default slot bindings | named slot 也可见 | 仅 default slot 可见 |
| Preprocessor 顺序 | markup×N, script×N, style×N | markup, script, style ×N(每个 preprocessor 内部三段) |
eslint-plugin-svelte3 |
推荐 | 弃用,改 eslint-plugin-svelte |
inert on outroing |
不应用 | 默认应用(无障碍改进) |
classList.toggle |
兼容老浏览器 | 需要 polyfill |
CustomEvent |
兼容老浏览器 | 需要 polyfill |
derived falsy 值 |
警告 | 抛错 |
svelte/internal 类型 |
暴露 | 已移除 |
svelte.JSX 命名空间 |
用 | 改 svelteHTML / svelte/elements |
库作者 peerDependencies |
^3 |
^3 || ^4 |
自动化脚本能处理的
tag=→customElement=(字符串形式)SvelteComponentTyped→SvelteComponentAction/ActionReturn泛型参数- Transitions 默认行为(添加
|global修饰符)
需要手动处理的
- Bundler
browsercondition 配置(Rollup / Webpack) - 严格类型错误的修复(
createEventDispatcherpayload) onMount异步清理改同步- Preprocessor
name属性 + 顺序调整 - ESLint 插件替换 + 配置迁移
derivedfalsy 值边界条件
Custom Element 升级
<!-- v3 --><svelte:options tag="my-counter" />
<!-- v4 --><svelte:options customElement={{ tag: 'my-counter', props: { initial: { type: Number } } }} />
onMount 异步清理反模式
// ❌ v4 报错且永远不清理
onMount(async () => { const data = await fetch('/api'); setup(data); return () => teardown(); });
// ✅ 同步返回值
onMount(() => { fetch('/api').then(setup); return () => teardown(); });
Preprocessor 顺序:MDsveX 必须最前
// svelte.config.js
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
import { mdsvex } from 'mdsvex';
export default {
preprocess: [
mdsvex({ name: 'mdsvex' }), // 先 markup 再 script
vitePreprocess({ name: 'vite' })
]
};
v3:所有 markup → 所有 script → 所有 style。v4:每个 preprocessor 内部 markup → script → style,再下一个。每个 preprocessor 必须声明
name。
库作者的 peerDependencies
{
"peerDependencies": { "svelte": "^3.0.0 || ^4.0.0" },
"devDependencies": { "svelte": "^4.0.0" }
}
Run-it-Yourself Checklist
npm install svelte@^4 # 1. 升级依赖
npx svelte-migrate@latest svelte-4 # 2. 跑迁移脚本
npx svelte-check # 3. 看 TypeScript
npm test # 4. 跑测试
如大量出现 Action 泛型错误,说明 migration 脚本漏掉;手动补 <HTMLElement, YourType>。
进一步 v5 迁移在 svelte-runes / svelte-misc 中;本技能只覆盖 Svelte 4 升级。
Quick Fixes
| 问题 | 解决 |
|---|---|
数组 .push() 不更新 |
items = [...items, newItem] 或 items = items |
| slot 样式不生效 | 样式隔离 scoped,不影响 slot 内容 |
$$restProps 类型错误 |
确认是 export let 而非 let |
| EventDispatcher 类型问题 | 升级 TypeScript 到 5+ |
FAQ
Q: 什么时候必须用 Legacy API? A: 维护未迁移的 Svelte 4 项目时。新项目应使用 Runes。
Q: 可以混合使用 Legacy 和 Runes 吗?
A: 可以。一个组件使用 $state 即进入 Runes Mode,未使用的部分用 Legacy 语法。
Q: $: 和 $derived 的区别?
A: 功能相似,但 $derived 是 Svelte 5 的 Runes API,更显式和可控。$: 在 Legacy Mode 可用。
Q: Slot 和 Snippet 哪个更好? A: Snippets 更强大灵活。Slot 适合简单内容传递;Snippet 可接收参数、可在定义处使用、类型安全更好。
Cross-References
本技能是 Svelte Legacy 维护专用,与以下技能协同:
- Svelte 5 入口与学习路径 → hand off to
svelte-awesomeskill. Install:npx skills add full-stack-skills/svelte-skills --skill svelte-awesome. - Svelte 4 → Svelte 5 迁移对照 → hand off to
svelte-miscskill(migration 章节). Install:npx skills add full-stack-skills/svelte-skills --skill svelte-misc. - Runes 响应式(
$state/$derived/$effect)→ hand off tosvelte-runesskill. Install:npx skills add full-stack-skills/svelte-skills --skill svelte-runes. - Stores(writable / readable / derived)→ hand off to
svelte-lifecycleskill. Install:npx skills add full-stack-skills/svelte-skills --skill svelte-lifecycle. - 模板语法(snippet / event / bind)→ hand off to
svelte-template-syntaxskill. Install:npx skills add full-stack-skills/svelte-skills --skill svelte-template-syntax. - 调试响应式不更新 /
$inspect→ hand off tosvelte-lifecycleskill. Install:npx skills add full-stack-skills/svelte-skills --skill svelte-lifecycle. - 把组件编译为 Web Component → hand off to
svelte-miscskill(Custom Elements 章节). Install:npx skills add full-stack-skills/svelte-skills --skill svelte-misc. - 初始化与迁移脚本 → hand off to
svelte-cliskill(sv migrate svelte-5). Install:npx skills add full-stack-skills/svelte-skills --skill svelte-cli.
Examples
Practical examples for working with Legacy APIs:
- examples/README.md - Examples entry point
- examples/migration-scripts.md - Migration workflows (svelte-migrate, let→$state, $:→$derived, etc.)
- examples/legacy-mode.md - Legacy mode usage, mixing legacy and runes
- examples/store-comparison.md - Store patterns in Svelte 4 and Svelte 5
- examples/migration-v4.md - Svelte 3 → Svelte 4 迁移 12 个实战示例(bundler 配置、严格类型、Custom Element、transition、slot、preprocessor 等)
References
Complete reference documentation:
- references/README.md - References entry point
- references/migration-reference.md - Complete migration reference with before/after code
- references/legacy-mode-reference.md - Legacy mode behavior and limitations
- references/store-reference.md - Store API reference (writable, readable, derived, custom stores)
- references/migration-v4-reference.md - Svelte 3 → Svelte 4 完整对照参考(最低版本、bundler、严格类型、Custom Element、slot、preprocessor、其他 breaking change、库作者指引)