codegen 阶段根据 AST 生成对应的 render 函数字符串。
<template> <div> <p>{{ message }}</p> <button @click="toggle">{{ isShown ? 'Hide' : 'Show' }}</button> </div> </template>解析器 (parse.ts) 将模板字符串解析成 AST。所有的 AST 节点定义都在 compiler-core/ast.ts 文件中,下面是一个元素节点的定义:
export interface BaseElementNode extends Node { type: NodeTypes.ELEMENT // 类型 ns: Namespace // 命名空间 默认为 HTML,即 0 tag: string // 标签名 tagType: ElementTypes // 元素类型 isSelfClosing: boolean // 是否是自闭合标签 例如 <br/> <hr/> props: Array<AttributeNode | DirectiveNode> // props 属性,包含 HTML 属性和指令 children: TemplateChildNode[] // 字节点 }转换器对 AST 进行优化和转换。AST结构:
{ type: 1, // 表示根节点 tag: 'div', children: [ { type: 1, tag: 'p', children: [ { type: 2, // 表示文本节点 content: '{{ message }}' } ] }, { type: 1, tag: 'button', children: [ { type: 2, content: '{{ isShown ? "Hide" : "Show" }}' } ], props: [ { type: 7, // 表示事件绑定 name: 'click', value: { type: 4, // 表示表达式节点 content: 'toggle' } } ] } ] }transfrom
const _hoisted_1 = { class: "text-red" }; const _hoisted_2 = { key: 0 }; // 堆代码 duidaima.com export function render(_ctx, _cache) { return ( openBlock(), createElementBlock("div", null, [ createVNode("p", null, toDisplayString(_ctx.message), 1 /* TEXT */), createVNode( "button", { onClick: _cache[0] || (_cache[0] = (...args) => _ctx.toggle && _ctx.toggle(...args)) }, toDisplayString(_ctx.isShown ? "Hide" : "Show"), 1 /* TEXT */ ) ]) ); }上述代码最后返回一个 render() 函数,作用是生成对应的 VNode。