Vue模板编译过程- optimize、generate

「这是我参与2022首次更文挑战的第25天,活动详情查看:2022首次更文挑战

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
  }
}
复制代码
  1. 创建CodegenState对象,就是代码生成过程中使用到的状态对象
  2. 判断ast是否存在
    • 存在:调用genElement开始生成代码
    • 不存在:_c("div") 字符串形式的代码
  3. 返回值

接下来让我们去关注静态根节点:staticRenderFns 生成的过程

CodegenState 类

CodegenState 类中我们需要重点关注的是staticRenderFnspre

  • 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

猜你喜欢

转载自juejin.im/post/7066666359974789133