vue compile源码实现
Vue 的模板编译(compile)是将模板字符串转换为渲染函数的过程,涉及解析、优化和代码生成三个阶段。以下是其核心实现原理的分析:
解析阶段(Parse)
将模板字符串转换为抽象语法树(AST),主要通过正则表达式和字符串处理完成。
模板解析示例:
<div id="app">{{ message }}</div>
会被解析为类似以下的 AST 结构:
{
type: 1, // 元素节点
tag: 'div',
attrsList: [{ name: 'id', value: 'app' }],
children: [{
type: 2, // 文本节点
expression: '_s(message)',
text: '{{ message }}'
}]
}
关键代码:
// src/compiler/parser/index.js
export function parse(template, options) {
const stack = []
let root
let currentParent
parseHTML(template, {
start(tag, attrs) {
// 处理开始标签
const element = createASTElement(tag, attrs)
if (!root) root = element
if (currentParent) currentParent.children.push(element)
stack.push(element)
currentParent = element
},
end() {
// 处理结束标签
stack.pop()
currentParent = stack[stack.length - 1]
},
chars(text) {
// 处理文本
if (currentParent) currentParent.children.push({ type: 3, text })
}
})
return root
}
优化阶段(Optimize)
标记静态节点和静态根节点,避免在重新渲染时重复处理。
静态节点标记:
- 通过
markStatic递归遍历 AST,标记所有静态节点(无动态绑定或指令)。 - 静态根节点是子节点全为静态的父节点。
关键代码:
// src/compiler/optimizer.js
export function optimize(root) {
markStatic(root)
markStaticRoots(root)
}
function markStatic(node) {
node.static = isStatic(node)
if (node.type === 1) {
node.children.forEach(child => {
markStatic(child)
if (!child.static) node.static = false
})
}
}
代码生成阶段(Generate)
将 AST 转换为可执行的渲染函数字符串。
代码生成示例: 对于 AST:
{
tag: 'div',
attrs: [{ name: 'id', value: '"app"' }],
children: [{ type: 2, expression: '_s(message)', text: '{{ message }}' }]
}
生成的渲染函数代码:
with(this) {
return _c('div', { attrs: { id: "app" } }, [_v(_s(message))])
}
关键代码:
// src/compiler/codegen/index.js
export function generate(ast) {
const code = ast ? genElement(ast) : '_c("div")'
return `with(this){return ${code}}`
}
function genElement(el) {
const children = genChildren(el)
const data = genData(el)
return `_c('${el.tag}'${data ? `,${data}` : ''}${children ? `,${children}` : ''})`
}
核心工具函数
_c: 创建虚拟 DOM 节点(createElement)。_v: 创建文本节点(createTextVNode)。_s: 转换为字符串(toString)。
// src/core/instance/render-helpers/index.js
export function installRenderHelpers(target) {
target._c = createElement
target._v = createTextVNode
target._s = toString
}
编译入口
通过 createCompiler 整合三个阶段:
// src/compiler/index.js
export const createCompiler = createCompilerCreator(function baseCompile(template, options) {
const ast = parse(template.trim(), options)
optimize(ast, options)
const code = generate(ast, options)
return { ast, render: code }
})
最终生成的渲染函数可通过 new Function 实例化,供组件渲染使用。







