Codegen(代码生成阶段)
编译管线最后阶段,将优化后的 AST 转换为可执行的目标代码(JavaScript)。各框架 Codegen 输出的代码结构差异巨大——Svelte 输出命令式 DOM 操作,React Compiler 输出带缓存包裹的原始组件,Vue 输出带 Patch Flags 的渲染函数,Qwik 输出多个懒加载 chunk 文件。
核心概念
Codegen(Code Generation)是编译管线三阶段(Parse → Transform → Codegen)的最后环节。Transform 阶段在 AST 上注入了优化标记和结构重写,Codegen 遍历这棵优化后的 AST,输出最终的 JavaScript 代码。
Codegen 的输出直接决定了三件事:运行时的执行模型(有无 VDOM diff)、调试体验(编译产物和源码的差距)、SSR 水合成本(编译产物是否含有 DOM 精确路径)。
各框架的 Codegen 输出特征
Svelte 5
输出命令式 DOM 操作代码——模板被转成 template() 静态克隆 + $.child() 精确 DOM 引用 + $.template_effect() signal→DOM 直接绑定。源码和编译产物差距最大,Source Map 精度最低。
Vue 3
输出带 Patch Flags 的渲染函数——createElementVNode("div", { class: cls }, "text", 2 /* CLASS */) 中的数字参数是 Transform 阶段注入的优化标记。静态提升的节点被提到渲染函数外部作为模块级常量。<script setup> 的逻辑代码几乎不变,调试体验好。
React Compiler
输出带缓存包裹的原始组件代码——_c(n) 分配缓存槽位,$[0] !== dep 做浅比较,命中缓存则跳过 JSX 创建。组件函数的整体结构保留,但多了编译器注入的缓存基础设施代码($ 数组和条件检查)。
Solid
输出模板克隆 + insert() 运行时订阅建立——和 Svelte 结构相似(都是命令式 DOM 操作),但关键差异在于 Solid 的 insert() 内部通过 createRenderEffect 在运行时动态建立依赖关系,而非编译期静态确定。
Qwik
唯一输出多个文件的编译器。主 bundle 中事件处理函数被替换为字符串引用("chunk-xxx.js#handler_0"),实际逻辑被拆到独立的懒加载 chunk 文件中。每个 chunk 包含 useLexicalScope 的闭包恢复代码。