菜单

迁移系统

相关源文件

迁移系统是一个工具,它提供了将 Svelte 组件从 Svelte 4 的语法自动转换为 Svelte 5 的基于 rune 的语法的能力。它执行了关键语法更改的转换,例如将 export let 转换为 $props(),将 $: 转换为 $derived$effect,将 on:event 转换为 onevent,以及将 <slot> 转换为 {@render ...}。此页面详细介绍了迁移系统的工作原理以及它执行的转换。

有关用户角度的实际迁移过程的信息,请参阅 Svelte 5 Migration Guide

概述

迁移系统旨在帮助开发人员将其代码迁移到 Svelte 5 的 rune API,而无需手动重写所有组件。它执行“尽最大努力”迁移,这意味着虽然它可以成功转换许多常见模式,但某些复杂代码可能需要在之后手动调整。

来源: packages/svelte/src/compiler/migrate/index.js115-457

迁移过程

迁移过程包括几个不同的阶段

  1. 解析源代码:系统首先使用现有的解析器解析 Svelte 组件。
  2. 组件分析:对解析后的 AST 进行分析,以了解其结构和依赖关系。
  3. 转换:应用各种转换来将代码转换为新语法。
  4. 代码生成:使用 MagicString 生成迁移后的代码,以实现精确的文本操作。
  5. 错误处理:如果迁移遇到问题,它会将原始代码包装在迁移任务注释中。

来源: packages/svelte/src/compiler/migrate/index.js115-457 packages/svelte/src/compiler/migrate/index.js27-113

关键转换

迁移系统处理许多语法转换,以将 Svelte 4 代码转换为 Svelte 5 代码。

反应式声明

最显著的变化之一是将反应式声明转换为 runes。

Svelte 4Svelte 5备注
let count = 0;let count = $state(0);顶层变量被转换为 state。
$: doubled = count * 2;const doubled = $derived(count * 2);简单的反应式声明变为派生值。
$: { /* side effects */ }$effect(() => { /* side effects */ });具有副作用的反应式块变为 effects。
export let prop;let { prop } = $props();Props 通过解构收集。
export let prop = 'default';let { prop = 'default' } = $props();默认值被保留。

来源: packages/svelte/src/compiler/migrate/index.js482-1037

事件和 DOM 属性

事件处理语法被完全转换。

Svelte 4Svelte 5备注
<button on:click={handler}><button onclick={handler}>事件指令成为常规属性。
<button on:click|preventDefault><button onclick={preventDefault(handler)}>事件修饰符通过辅助函数进行处理。
<button on:click><button {onclick}>事件转发变为属性转发。

来源: packages/svelte/src/compiler/migrate/index.js1053-1037

Slots 和 Snippets

Slots 被转换为新的 snippet 系统。

Svelte 4Svelte 5备注
<slot />{@render children?.()}默认 slot 变为 children snippet 渲染。
<slot name="header" />{@render header?.()}命名 slot 变为命名 snippet。
<div slot="header">...</div>{#snippet header()}..{/snippet}Slot 用法变为 snippet 声明。

来源: packages/svelte/src/compiler/migrate/index.js1061-1071 packages/svelte/tests/migrate/samples/slots/output.svelte1-28

组件和 CSS

迁移系统还处理特定组件的转换。

来源: packages/svelte/src/compiler/migrate/index.js41-96 packages/svelte/src/compiler/migrate/index.js155-456

CSS 迁移

迁移系统还处理 CSS 转换,特别是关于全局选择器和伪选择器。

来源: packages/svelte/src/compiler/migrate/index.js41-96

错误处理和限制

并非所有代码都可以自动迁移。迁移系统会识别需要手动干预的情况,并添加适当的注释。

需要手动干预的常见场景

  1. 使用 beforeUpdateafterUpdate 生命周期钩子的组件。
  2. 复杂使用 createEventDispatcher
  3. 具有无法安全转换的复杂响应式模式的组件。

来源: packages/svelte/src/compiler/migrate/index.js440-456

实现细节

迁移系统使用了几个关键库和技术。

  1. MagicString:用于精确的代码操作,允许插入、删除和替换而不影响周围代码。
  2. zimmerframe:一个用于 AST 遍历和转换的库。
  3. AST 分析:系统分析抽象语法树 (AST) 以理解代码结构。

状态管理

在迁移过程中,系统会跟踪各种信息。

来源: packages/svelte/src/compiler/migrate/index.js459-480

AST 访问器的技术细节

迁移系统使用 AST 访问器来转换代码。以下是关键访问器的概述:

实例脚本访问器

instance_script 访问器处理组件脚本部分的转换。

  1. Import Declaration:处理来自“svelte”和其他来源的导入。
  2. Variable Declaration:将 let 转换为 $state 并提取 props。
  3. Labeled Statement:将 $: 语句转换为 $derived$effect
  4. Export Named Declaration:处理 exports。
  5. Break Statement:转换反应式块中的 break 语句。

来源: packages/svelte/src/compiler/migrate/index.js482-1037

模板访问器

template 访问器处理组件模板中的转换。

  1. Regular Element:处理元素转换。
  2. Svelte Self:将 <svelte:self> 转换为导入组件。
  3. Identifier:处理模板中的标识符。

来源: packages/svelte/src/compiler/migrate/index.js1053-1071

迁移脚本架构

来源: packages/svelte/src/compiler/migrate/index.js115-457 packages/svelte/src/compiler/migrate/index.js459-480

挑战和边缘情况

迁移系统处理了几个具有挑战性的场景。

类型注解

对于 TypeScript 组件,系统会尝试保留类型信息。

对于具有大量 props 的组件,它会生成一个接口或 JSDoc 类型。

来源: packages/svelte/tests/migrate/samples/props-ts/output.svelte1-37 packages/svelte/tests/migrate/samples/jsdoc-with-comments/output.svelte1-57

JSDoc 注释

系统通过将 JSDoc 注释转移到迁移后的代码来保留它们

来源: packages/svelte/tests/migrate/samples/jsdoc-with-comments/input.svelte1-52 packages/svelte/tests/migrate/samples/jsdoc-with-comments/output.svelte1-57

组件实例

迁移系统通过创建适当的动态组件来处理 <svelte:component> 用法的转换

来源: packages/svelte/tests/migrate/samples/svelte-component/output.svelte1-243

结论

迁移系统为将 Svelte 代码更新到新的 Svelte 5 语法提供了一个强大的工具。虽然它可以处理许多常见模式,但开发人员应审查迁移后的代码,并解决注释指示的任何迁移任务。该系统在自动化转换和保留代码的原始意图之间取得了平衡,使迁移过程更易于管理。