本文档概述了 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
解析阶段读取 .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的根节点包含:
<script> 标签中声明的 JavaScript。<script module> 标签中声明的 JavaScript。<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})。 |
| AwaitBlock | Promise 处理({#await})。 |
| KeyBlock | 动画控制({#key})。 |
| SnippetBlock | 可重用的模板片段({#snippet})。 |
来源:packages/svelte/src/compiler/types/template.d.ts37-115 packages/svelte/src/compiler/types/template.d.ts273-457
分析阶段会检查 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 | 控制流块中的变量。 |
每个作用域维护:
来源:packages/svelte/src/compiler/phases/scope.js24-106 packages/svelte/src/compiler/phases/scope.js366-556
对于使用 runes 的组件,分析阶段会:
$state、$derived、$effect、$props)。来源:packages/svelte/src/compiler/phases/2-analyze/visitors/CallExpression.js15-66
分析阶段还处理样式:
:global() 选择器。来源:packages/svelte/src/compiler/phases/2-analyze/css/css-analyze.js16-276
转换阶段将分析过的 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 转换过程会:
:global() 选择器。来源:packages/svelte/src/compiler/phases/3-transform/css/index.js29-69
对于客户端渲染,转换阶段会生成:
对于服务器端渲染,它会生成
编译器包含一个全面的错误和警告系统,以帮助开发人员识别其 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 | 是否包含调试代码 |
css | CSS 处理:'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 版本构建的组件
createClassComponent 和 asClassComponent 将基于类的旧组件转换为新版本。来源: packages/svelte/src/legacy/legacy-client.js14-59 packages/svelte/tests/runtime-legacy/shared.ts1-66
编译器可以以两种模式运行
$:)$state、$derived、$effect、$props)编译器可以根据代码中是否存在符文自动检测要使用的模式,也可以使用 runes 选项显式设置。
来源: packages/svelte/src/compiler/phases/2-analyze/index.js398-413
Svelte 编译器被构建为一个包含三个主要阶段的管道:解析、分析和转换。这种架构允许它有效地将 Svelte 组件转换为高度优化的 JavaScript,同时最小化运行时开销。阶段之间的关注点分离使得编译器易于维护和扩展,同时提供全面的错误报告,帮助开发人员编写正确、高性能的组件。