菜单

编译器架构

相关源文件

本文档概述了 Svelte 编译器的架构,解释了其结构、阶段和关键组件。编译器负责将 .svelte 文件转换为可在浏览器中运行的优化 JavaScript。有关执行编译代码的运行时系统的信息,请参阅 运行时系统

编译器管道概述

Svelte 编译器通过三个阶段将 .svelte 组件文件转换为优化的 JavaScript。它解析组件源代码,分析其正确性和优化机会,然后将其转换为可执行代码。

来源:packages/svelte/src/compiler/index.js1-24

主入口点

编译器暴露两个主要函数:

  • compile(source, options):将 .svelte 组件转换为 JavaScript 和 CSS。
  • compileModule(source, options):将带有 runes 的 JavaScript 模块转换为优化后的模块。

这些函数初始化编译过程并协调三个阶段的流程。

编译器根据 generate 选项生成不同类型的输出:

  • 'client':为浏览器设计(默认)。
  • 'server':用于服务器端渲染。
  • false:不生成代码(仅用于验证)。

来源:packages/svelte/src/compiler/index.js15-24 packages/svelte/src/compiler/types/index.d.ts181-196

1. 解析阶段

解析阶段读取 .svelte 源代码并构建抽象语法树(AST)。此 AST 表示组件的结构,包括 HTML 元素、脚本内容、样式定义和 Svelte 特有构造。

来源:packages/svelte/src/compiler/phases/1-parse/state/element.js51-406 packages/svelte/src/compiler/phases/1-parse/state/tag.js14-411

AST 结构

AST的根节点包含:

  • Fragment:组件的 HTML 模板。
  • Instance script:在 <script> 标签中声明的 JavaScript。
  • Module script:在 <script module> 标签中声明的 JavaScript。
  • CSS:在 <style> 标签中声明的样式。

AST 区分了不同类型的元素:

元素类型描述
RegularElement常规 HTML 元素,例如 <div><span>
组件自定义组件(PascalCase 命名)。
SvelteElement动态元素(<svelte:element>)。
SvelteComponent动态组件(<svelte:component>)。
SpecialElements特殊元素,例如 <svelte:head><svelte:body>
SlotElement插槽元素(<slot>)。

AST 还包含控制流块和表达式:

块类型描述
IfBlock条件渲染({#if})。
EachBlock列表渲染({#each})。
AwaitBlockPromise 处理({#await})。
KeyBlock动画控制({#key})。
SnippetBlock可重用的模板片段({#snippet})。

来源:packages/svelte/src/compiler/types/template.d.ts37-115 packages/svelte/src/compiler/types/template.d.ts273-457

2. 分析阶段

分析阶段会检查 AST,以验证其正确性、识别优化机会并为变量和绑定创建作用域信息。此阶段对于确保组件按预期工作以及启用后续优化至关重要。

来源:packages/svelte/src/compiler/phases/2-analyze/index.js187-896 packages/svelte/src/compiler/phases/scope.js366-556

关键分析函数

  • analyze_component(root, source, options):组件分析的主函数。
  • analyze_module(ast, options):分析带有 runes 的 JavaScript 模块。

作用域管理

分析创建作用域层次结构,跟踪:

作用域类型描述
Module Scope来自 <script module> 的变量。
Instance Scope来自 <script> 的变量。
Template Scope组件模板中的变量。
Block Scopes控制流块中的变量。

每个作用域维护:

  • Declarations:作用域中声明的变量。
  • References:引用变量的位置。
  • Bindings:声明和引用之间的连接。

来源:packages/svelte/src/compiler/phases/scope.js24-106 packages/svelte/src/compiler/phases/scope.js366-556

Runes 分析

对于使用 runes 的组件,分析阶段会:

  • 识别 rune 的使用($state$derived$effect$props)。
  • 验证其正确使用和放置。
  • 跟踪响应性关系。
  • 报告无效使用的错误。

来源:packages/svelte/src/compiler/phases/2-analyze/visitors/CallExpression.js15-66

CSS 分析

分析阶段还处理样式:

  • 将 CSS 选择器作用域化到组件。
  • 识别关键帧。
  • 处理 :global() 选择器。
  • 处理 CSS 优化。

来源:packages/svelte/src/compiler/phases/2-analyze/css/css-analyze.js16-276

3. 转换阶段

转换阶段将分析过的 AST 转换为用于客户端渲染、服务器端渲染或两者的优化 JavaScript 代码。它还处理和转换 CSS。

来源:packages/svelte/src/compiler/phases/3-transform/css/index.js29-69 packages/svelte/src/compiler/phases/3-transform/client/visitors/EachBlock.js1-11

CSS 转换

CSS 转换过程会:

  1. 将 CSS 选择器添加到组件以作用域化样式。
  2. 处理关键帧。
  3. 处理 :global() 选择器。
  4. 优化和压缩 CSS(在适当的情况下)。

来源:packages/svelte/src/compiler/phases/3-transform/css/index.js29-69

客户端转换

对于客户端渲染,转换阶段会生成:

  • DOM 创建和操作代码。
  • 响应式系统实现
  • 事件处理程序
  • 生命周期钩子
  • 动画和过渡代码

服务器端转换

对于服务器端渲染,它会生成

  • 静态 HTML 生成代码
  • 用于客户端重新水合的水合提示

错误与警告系统

编译器包含一个全面的错误和警告系统,以帮助开发人员识别其 Svelte 组件中的问题。

来源: packages/svelte/src/compiler/errors.js1-46 packages/svelte/src/compiler/warnings.js1-44

每个错误和警告都包含

  • 唯一的错误/警告代码
  • 描述性消息
  • 源位置信息(开始和结束位置)
  • 文档链接

错误会立即抛出,停止编译,而警告会被收集并与编译结果一起返回。

常见的错误类别包括

  • 无效的语法或结构
  • 符文使用不当
  • 可访问性问题
  • 响应式问题
  • 组件结构问题

来源: packages/svelte/messages/compile-errors/template.md1-53 packages/svelte/messages/compile-errors/script.md1-3

编译器选项

编译器接受各种选项来定制其行为

选项描述
generate输出目标:'client'、'server' 或 false
dev是否包含调试代码
cssCSS 处理:'injected' 或 'external'
immutable数据是否被视为不可变的
runes启用或推断 runes 模式
customElement编译为自定义元素
namespace元素命名空间 (html, svg, mathml)
accessors为 props 生成 getter/setter
preserveComments保留 HTML 注释
preserveWhitespace在模板中保留空格

来源: packages/svelte/src/compiler/types/index.d.ts60-179 packages/svelte/src/compiler/types/index.d.ts181-209

编译结果

编译结果包括

来源: packages/svelte/src/compiler/types/index.d.ts6-43

遗留支持和迁移

编译器支持使用早期 Svelte 版本构建的组件

  • 可以使用 createClassComponentasClassComponent 将基于类的旧组件转换为新版本。
  • 兼容模式有助于在 Svelte 4 和 Svelte 5 之间进行迁移
  • 已弃用模式的验证警告

来源: packages/svelte/src/legacy/legacy-client.js14-59 packages/svelte/tests/runtime-legacy/shared.ts1-66

Runes 模式

编译器可以以两种模式运行

  1. 经典模式:使用 Svelte 4 的响应式模型和响应式声明($:
  2. 符文模式:使用 Svelte 5 的细粒度响应式和符文($state$derived$effect$props

编译器可以根据代码中是否存在符文自动检测要使用的模式,也可以使用 runes 选项显式设置。

来源: packages/svelte/src/compiler/phases/2-analyze/index.js398-413

结论

Svelte 编译器被构建为一个包含三个主要阶段的管道:解析、分析和转换。这种架构允许它有效地将 Svelte 组件转换为高度优化的 JavaScript,同时最小化运行时开销。阶段之间的关注点分离使得编译器易于维护和扩展,同时提供全面的错误报告,帮助开发人员编写正确、高性能的组件。