前言:

上一篇虚拟DOM中讲到一个必不可少的条件VNode,VNode是从哪里来的呢?这就是本篇文章讲的重点。把用户写的模板进行编译,就会产生VNode。


什么是模板编译?

我们把 template 标签中类似于原生html的内容称之为模板。vue会把用户在template标签中写的类似于原生html的内容进行编译,把原生html的内容找出来,再把非原生html找出来,经过一系列的逻辑处理生成渲染函数,也就是render函数的这一段过程称之为模板编译过程。
简单来说模板编译过程就是把用户写的模板经过一系列处理最终生成render函数的过程。


抽象语法树AST

Vue如何解析template标签中写的模板内容的呢,需要借助一个叫做抽象语法树的东西。
抽象语法树(AbstractSyntaxTree,AST)简称语法树,是源代码语法结构的一种抽象表示。它以树状的形式表现编程语言的语法结构,树上的每个节点都表示源代码中的一种结构。将源代码转换为AST后,就可以对AST进行很多操作。
将一堆字符串模板解析成抽象语法树AST后,用处理后的AST来生成render函数。


具体流程

具体流程可大致分为三个阶段:

  • 模板解析阶段:将一堆模板字符串用正则等方式解析成抽象语法树AST;源码路径:src/compiler/parser/index.js;
  • 优化阶段:遍历AST,找出其中的静态节点,并打上标记;源码路径:src/compiler/optimizer.js;
  • 代码生成阶段:将AST转换成渲染函数;源码路径:src/compiler/codegen/index.js;
    源码核心代码为:
export const createCompiler = createCompilerCreator(function baseCompile (
  template: string,
  options: CompilerOptions
): CompiledResult {
  //模板解析阶段:用正则等方式解析template模板中的指令、class、style等数据,形成AST
  const ast = parse(template.trim(), options)
  if (options.optimize !== false) {
    //优化阶段:遍历AST,找出其中的静态节点,并打上标记;
    //对静态节点做标记,挡在进行patch的过程中,DOM-Diff算法会直接跳过静态节点,
    //从而减少了比较的过程,优化了patch的性能
   optimize(ast, options)
  }
  //代码生成阶段:将AST转换成渲染函数
  // 得到的是render函数的字符串以及staticRenderFns(静态渲染函数)字符串
  const code = generate(ast, options)
  return {
    ast,
    render: code.render,
    staticRenderFns: code.staticRenderFns
  }
})

流程图:

vue 的 template 转json_语法树


其中解析器流程为: 解析器主线函数parse中先调用HTML解析器parseHTML函数对模板字符串进行解析,如果在解析过程中遇到文本或过滤器信息则在调用对应的文本解析器parseText函数或过滤器解析器parseFilters函数,具体看源码。

优化器的作用主要是找出模板中所有的静态节点和静态根节点并打上标记。源码位置:src/compiler/optimizer.js

代码生成,生成render函数字符串,vue只要调用了render函数,就可以把模板转换成对应的虚拟DOM。具体看源码src/compiler/codegen/index.js