Vue模板编译过程- optimize、generate
optimize 与 generate 函数
接下来我们要进行查看 Vue 中 如何把优化好的 ast
对象转换为 js
代码
optimize 函数
-
优化抽象语法树,检测子节点中是否是纯静态节点
-
一旦检测到纯静态节点,例如:
<div>Hello </div>
永远不会更改的节点
- 提升为常量,重新渲染的时候不在重新创建节点
- 在 patch 的时候直接跳过静态子树
generate
函数-参数
generate
函数: 接受两个参数:
ast
: 优化好的ast
对象,options
: 选项对象 返回的code
就是js
代码
// 把抽象语法树生成字符串形式的 js 代码
const code = generate(ast, options)
generate 解析
这个函数从行数上来看非常的简单,就三句话
export function generate (
ast: ASTElement | void,
options: CompilerOptions
): CodegenResult {
const state = new CodegenState(options)
const code = ast ? genElement(ast, state) : '_c("div")'
return {
render: `with(this){return ${code}}`,
staticRenderFns: state.staticRenderFns
}
}
- 创建
CodegenState
对象,就是代码生成过程中使用到的状态对象 - 判断
ast
是否存在- 存在:调用
genElement
开始生成代码 - 不存在:
_c("div")
字符串形式的代码
- 存在:调用
- 返回值
接下来让我们去关注静态根节点:staticRenderFns
生成的过程
CodegenState 类
CodegenState
类中我们需要重点关注的是staticRenderFns
、pre
staticRenderFns
:用来存储静态根节点生成的代码,因为一个模板中可能有多个静态根节点pre
: 用来记录当前处理的节点是否使用v-pre
标记的 当我们创建完毕对应的类之后,就会调用genElement
进行state.staticRenderFns
的数据添加动作
genElement 方法
export function genElement (el: ASTElement, state: CodegenState): string {
if (el.parent) {
el.pre = el.pre || el.parent.pre
}
if (el.staticRoot && !el.staticProcessed) {
return genStatic(el, state)
}
...
}
在 genStatic
中我们会为静态节点添加上对应的数据
function genStatic (el: ASTElement, state: CodegenState): string {
...
state.staticRenderFns.push(`with(this){return ${genElement(el, state)}}`)
...
}
state.staticRenderFns
是数组是因为一个模板中可能有多个静态子节点,接着就需要进行调用_m
方法,具体内容在src\core\instance\render-helpers\index.js
中
转载自:https://juejin.cn/post/7066666359974789133