AST(抽象语法树)

编译器将源代码转换为树状数据结构的中间表示。源码的每个语法元素(变量声明、函数调用、模板绑定等)对应树上的一个节点,编译器的后续优化和代码生成都基于对 AST 的遍历和变换。

核心概念

AST 是编译器 Parse 阶段的产物——将线性的源代码文本转换为结构化的树形数据,让后续的 Transform 和 Codegen 阶段可以用程序化的方式分析和修改代码结构。

一段简单的 JSX <button onClick={handler}>{count}</button> 被解析后,AST 大致结构为:

text
JSXElement
├─ openingElement: JSXOpeningElement
│   ├─ name: "button"
│   └─ attributes: [JSXAttribute(name="onClick", value=handler)]
├─ children: [JSXExpressionContainer(expression=count)]
└─ closingElement: JSXClosingElement(name="button")

编译器对 AST 的遍历和修改(而非对源码字符串的正则替换)是所有现代前端编译器的基础——它保证了代码变换的结构正确性

各框架编译器的 AST 差异

不同框架的 AST 节点类型反映了各自的语言特性:

  • Svelte:自定义 AST,包含 FragmentExpressionTagEachBlockIfBlock 等模板专用节点。$state 在 AST 里标记为特殊的 rune 声明
  • Vue:模板 AST 包含 ElementInterpolationForNodeIfNode 等节点。SFC 有两层 AST——<script> 部分用 Babel AST,<template> 部分用模板编译器自己的 AST
  • Solid / React:使用标准 Babel AST(JSXElementJSXAttribute 等),没有自定义节点类型。编译差异完全在 Transform 阶段产生,Parse 阶段几乎相同
  • Qwik:同样基于标准 JS/TS AST,但 Parse 阶段会识别 $ 后缀标记并在 AST 上添加元数据,为后续的代码拆分做准备

关键差异:Svelte 和 Vue 因为有自定义模板语法,需要自定义解析器生成专用 AST;Solid、React、Qwik 使用标准 JS 解析器(Babel),AST 结构通用。这意味着 Svelte/Vue 的编译管线从 Parse 阶段就开始分化,而 Solid/React/Qwik 的分化点在 Transform 阶段。

引用本术语的文章