菜单

转换阶段

相关源文件

转换阶段是 Svelte 编译器管道中的第三个主要阶段。它接收来自分析阶段的已分析抽象语法树 (AST),并将其转换为用于客户端、服务器或两者兼有的优化 JavaScript 代码。此阶段负责生成高效的运行时代码,这些代码实现 Svelte 的响应式系统、DOM 操作和组件生命周期,同时保留原始 Svelte 组件的意图。

有关前几个阶段的信息,请参阅解析阶段分析阶段

概述

转换阶段是 Svelte 的编译时魔法真正发生的地方。它将组件的抽象表示转换为可执行的 JavaScript,这些 JavaScript 可以在状态更改时有效地更新 DOM。转换通过一系列访问器完成,这些访问器处理不同类型的 AST 节点并生成相应的 JavaScript。

来源

  • packages/svelte/src/compiler/phases/2-analyze/index.js
  • packages/svelte/src/compiler/index.js
  • packages/svelte/src/compiler/types/index.d.ts

输入和输出

输入

  • 来自分析阶段的带有元数据的 AST
  • 组件选项(来自编译器选项和/或<svelte:options>
  • 变量和绑定的作用域信息

输出

  • 客户端 JavaScript(用于浏览器渲染)
  • 服务器 JavaScript(用于服务器端渲染)
  • 已应用作用域的优化 CSS

来源

  • packages/svelte/src/compiler/index.js
  • packages/svelte/src/compiler/types/index.d.ts

转换过程

转换过程涉及使用访问器模式遍历 AST,其中专门的访问器函数处理不同类型的 AST 节点。这种方法允许基于节点类型的模块化代码生成策略。

来源

  • packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js
  • packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/utils.js
  • packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/element.js
  • packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/component.js

访问器模式

转换阶段严重依赖于访问器模式实现,其中 AST 中的每个节点类型都有一个相应的访问器函数。这些访问器负责为该节点类型生成适当的 JavaScript 代码。

来源

  • packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js
  • packages/svelte/src/compiler/phases/3-transform/client/visitors/EachBlock.js
  • packages/svelte/src/compiler/phases/3-transform/client/visitors/SvelteElement.js

关键转换领域

元素转换

常规 HTML 元素被转换为高效的 DOM 创建和更新操作。这包括处理静态和动态属性、类、样式和事件处理程序。

来源

  • packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js
  • packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/element.js
  • packages/svelte/src/internal/client/dom/elements/attributes.js

元素转换过程包括

  1. 创建初始 HTML 模板
  2. 生成设置动态属性和属性的代码
  3. 设置事件处理程序
  4. 为响应式属性创建更新逻辑

例如,RegularElement 访问器packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js41-453 处理 HTML 元素的转换,通过

  • 生成模板的静态 HTML
  • 为动态属性创建属性设置器
  • 设置类和样式指令
  • 处理输入、文本区域和选择框的特殊情况

属性处理

属性根据其类型以及是静态还是动态进行不同的处理

来源

  • packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/element.js
  • packages/svelte/src/internal/client/dom/elements/attributes.js

属性转换代码处理几种情况

  • 静态属性直接放入 HTML 模板
  • 动态属性需要更新逻辑
  • classstyle 等特殊属性有专门的处理程序
  • 自定义元素会获得特殊处理

例如,set_attributes 函数packages/svelte/src/internal/client/dom/elements/attributes.js268-450 处理属性的运行时应用,仔细管理 HTML 属性和 DOM 属性之间的差异。

组件转换

组件被转换以创建实例、传递 props、处理事件和管理插槽

来源

  • packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/component.js

组件转换过程

  1. 创建实例化组件实例的代码
  2. 处理 props 并将其传递给组件
  3. 为组件事件设置事件处理程序
  4. 处理插槽及其内容

控制流转换

{#if}{#each}{#await} 等控制流结构被转换为响应式代码,从而高效地更新 DOM。

来源

  • packages/svelte/src/compiler/phases/3-transform/client/visitors/EachBlock.js

例如,EachBlock 转换packages/svelte/src/compiler/phases/3-transform/client/visitors/EachBlock.js 处理创建高效的迭代逻辑,当迭代数组更改时,该逻辑可以仅更新已更改的项目。

表达式转换

模板中的表达式(例如{variable})被转换为响应式代码。

来源

  • packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/utils.js

表达式的转换过程包括

  1. 分析表达式以确定它是否包含响应式状态
  2. 根据表达式类型创建适当的更新逻辑
  3. 优化某些类型的表达式(例如简单的属性访问)

例如,build_template_chunk 函数packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/utils.js39-120 处理模板内容的静态和动态部分的组合,决定何时使用模板文字而不是直接值。

运行时集成

转换阶段生成的代码与 Svelte 的运行时集成,以创建高效的更新机制。

来源

  • packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/utils.js
  • packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js

生成的代码通过诸如以下之类的实用函数与 Svelte 的运行时进行交互:

  • $.effect - 用于响应式和跟踪更新
  • $.template_effect - 用于优化的模板更新
  • $.set_attribute - 用于高效的属性设置
  • $.child - 用于遍历和更新子元素

优化策略

转换阶段采用多种优化策略来生成高效的代码

1. 静态内容提取

模板的静态部分被识别并直接包含在 HTML 模板中,从而避免在运行时进行不必要的 DOM 创建。

2. 表达式记忆化

复杂的表达式被记忆化,以避免不必要的重新计算。

来源

  • packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/utils.js

3. 批量更新

相关的更新被批量处理,以最大程度地减少 DOM 操作。

4. 模板重用

对于列表项中的重复结构,例如在{#each}块中,模板会被重用以提高效率。

5. 特殊 DOM 操作

根据上下文使用不同的 DOM 操作以获得最佳性能

  • 对某些属性的直接属性赋值
  • setAttribute 用于标准属性
  • classstyle 属性的特殊处理

来源

  • packages/svelte/src/internal/client/dom/elements/attributes.js
  • packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/element.js

关键生成的代码结构

转换阶段通常会生成四个主要的代码部分

1. 模板 HTML

2. 初始化代码

3. 更新代码

4. Effect 创建

来源

  • packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/utils.js
  • packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js

特殊处理情况

自定义元素

自定义元素在转换过程中会获得特殊处理,以正确支持属性设置与属性设置

来源

  • packages/svelte/src/internal/client/dom/elements/attributes.js

表单元素

表单元素,如输入框、选择框和文本区域,会有特殊处理,以正确管理它们的值和选中状态。

来源

  • packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js

类型注意事项

转换阶段处理 TypeScript 注释,在代码生成阶段基本忽略它们,因为它们在分析阶段已经处理过。

总结

转换阶段是将 Svelte 将已分析的组件结构转换为高效运行时代码的关键阶段。它

  1. 将已分析的 AST 转换为优化后的 JavaScript
  2. 生成高效的 DOM 创建和更新逻辑
  3. 创建响应式代码以处理状态更改
  4. 通过静态提取和记忆化等策略进行性能优化
  5. 生成与 Svelte 运行时集成的代码

正是这个阶段使得 Svelte 的响应式方法独一无二且性能卓越,生成最少的代码,仅在状态更改时更新需要更新的部分。

来源

  • packages/svelte/src/compiler/index.js
  • packages/svelte/src/compiler/types/index.d.ts
  • packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js
  • packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/utils.js