从 Svelte 4 迁移
Svelte 5 几乎完全向后兼容 Svelte 4。你可以渐进式迁移,旧的写法(legacy mode)和新的 Runes 可以在同一项目里共存。本章给出主要变化与迁移步骤。
迁移策略
推荐渐进式而非一次性重写:
- 先升级依赖到 Svelte 5,确认项目能跑(此时用的是兼容/legacy 模式)
- 逐个组件改用 Runes
- 用官方 codemod 自动转换大部分语法
升级依赖
bash
npm install svelte@latest
# SvelteKit 项目同时升级
npm install @sveltejs/kit@latest @sveltejs/vite-plugin-svelte@latest确认版本:
bash
npm ls svelte # 应显示 5.x使用官方迁移工具(codemod)
Svelte 团队提供了自动迁移工具,能把大部分 Svelte 4 语法转成 Runes:
bash
npx sv migrate它会交互式地处理 export let → $props、$: → $derived/$effect、on: → 事件属性等转换。转换后仍需人工复核。
主要语法变化对照
1. 响应式状态
svelte
<!-- Svelte 4 -->
<script>
let count = 0;
</script>
<!-- Svelte 5 -->
<script>
let count = $state(0);
</script>2. 派生值
svelte
<!-- Svelte 4 -->
<script>
let count = 0;
$: doubled = count * 2;
</script>
<!-- Svelte 5 -->
<script>
let count = $state(0);
let doubled = $derived(count * 2);
</script>3. 副作用
svelte
<!-- Svelte 4 -->
<script>
let count = 0;
$: console.log(count);
</script>
<!-- Svelte 5 -->
<script>
let count = $state(0);
$effect(() => console.log(count));
</script>4. Props
svelte
<!-- Svelte 4 -->
<script>
export let title;
export let count = 0;
</script>
<!-- Svelte 5 -->
<script>
let { title, count = 0 } = $props();
</script>5. 事件
svelte
<!-- Svelte 4 -->
<button on:click={handleClick}>点我</button>
<!-- Svelte 5 -->
<button onclick={handleClick}>点我</button>6. 组件自定义事件
svelte
<!-- Svelte 4 -->
<script>
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();
</script>
<button on:click={() => dispatch('notify', data)}>通知</button>
<!-- Svelte 5 -->
<script>
let { onnotify } = $props();
</script>
<button onclick={() => onnotify(data)}>通知</button>7. Slots → Snippets
svelte
<!-- Svelte 4 -->
<slot />
<slot name="header" />
<!-- Svelte 5 -->
<script>let { children, header } = $props();</script>
{@render children()}
{@render header?.()}8. 双向绑定的 props
svelte
<!-- Svelte 4 -->
<script>
export let value; // 父组件 bind:value 即可改
</script>
<!-- Svelte 5 -->
<script>
let { value = $bindable() } = $props(); // 显式声明可绑定
</script>9. 挂载 API
js
// Svelte 4
const app = new App({ target: document.body });
// Svelte 5
import { mount } from 'svelte';
const app = mount(App, { target: document.body });完整对照表
| 主题 | Svelte 4 | Svelte 5 |
|---|---|---|
| 状态 | let x = 0 | let x = $state(0) |
| 派生 | $: y = x * 2 | let y = $derived(x * 2) |
| 副作用 | $: sideEffect() | $effect(() => sideEffect()) |
| Props | export let p | let { p } = $props() |
| 可绑定 prop | export let v(配 bind:) | let { v = $bindable() } = $props() |
| DOM 事件 | on:click | onclick |
| 组件事件 | createEventDispatcher | 回调 props(onxxx) |
| 内容分发 | <slot> | {@render children()} |
| 具名内容 | <slot name="x"> | Snippets {#snippet x()} |
| 挂载 | new App({ target }) | mount(App, { target }) |
| 深度响应式 | 需重新赋值 | Proxy 自动深度追踪 |
深度响应式的行为变化
这是迁移时最容易踩坑的地方。Svelte 4 需要「重新赋值」来触发更新:
svelte
<!-- Svelte 4:必须重新赋值 -->
<script>
let user = { name: '张三' };
function rename() {
user.name = '李四';
user = user; // ← 手动触发更新(或 user = {...user})
}
</script>Svelte 5 的 $state 是深度响应式的,不需要这行:
svelte
<!-- Svelte 5 -->
<script>
let user = $state({ name: '张三' });
function rename() {
user.name = '李四'; // 直接生效
}
</script>迁移检查清单
- [ ] 升级
svelte到 5.x,项目能正常构建运行 - [ ] 运行
npx sv migrate自动转换 - [ ] 把
export let改为$props()解构 - [ ] 把
$:改为$derived/$effect - [ ] 把
on:事件改为on事件属性 - [ ] 把
createEventDispatcher改为回调 props - [ ] 把
<slot>改为 Snippets +{@render} - [ ] 把需要双向绑定的 prop 加上
$bindable - [ ] 删除多余的
x = x手动触发更新的代码 - [ ] 用
npx svelte-check检查类型与编译错误
参考
- 官方迁移指南:https://svelte.dev/docs/svelte/v5-migration-guide
- Runes 总览:https://svelte.dev/docs/svelte/what-are-runes
下一步
有疑问?看常见问题。