# 简介

在上一章节中,我们详细讲述了虚拟DOM的相关知识,其中大部分都是虚拟DOM拿到vnode之后所做的事情。那么vnode是怎样生成的呢?这就涉及到我们本章节要研究的内容模板编译

# 完整渲染流程

我们在平时使用Vue的开发过程中,可以在模板中使用变量填充,也可以在模板中直接使用JavaScript表达式或者使用自定义的指令等。

这些功能在标准的HTML语法中是不存在的,那为什么会在浏览器正确的展示出来呢,要探究这个问题,我们需要先了解下 Vue 完整渲染流程。

完整渲染流程

  1. 用户编写模板:用户通过Vue提供的模板语法声明式的描述界面
  2. 模板编译:Vue将用户编写的模板进行解析和处理
  3. render函数:模板编译完成后,输出的就是render函数
  4. vnode:执行render函数,生成vnode
  5. patch:通过diff算法等操作对vnode树进行处理
  6. 视图: 处理完毕后的vnode树生成真实的视图

在这个流程中,我们将前三个阶段称为模板编译阶段,后三个阶段称为虚拟DOM阶段

所以我们可以得出一个结论,浏览器能够正确渲染出我们使用的模板语法的原因就是Vue在渲染过程中使用了模板编译,而模板编译就是将用户编写的模板通过一系列处理最终生成render函数的过程。

# AST

我们都知道,我们在<template></template>标签中写的模板对Vue来说就是一堆字符串,那么如何解析这一堆字符串并且从中提取出元素的标签、属性、变量插值等有效信息呢?这就需要借助一个叫做抽象语法树(AST)的东西。

抽象语法树(AbstractSyntaxTree,AST),简称语法树(Syntax tree),是源代码的抽象语法结构的树状表现形式。一个 AST 只包含与分析源文本有关的信息,而跳过任何其他在解析文本时使用的额外内容(例如什么分号,函数参数中的逗号之类的对程序没有意义的东西)

简单来说,如果虚拟DOM是用js对象表示真实DOM,那么AST就是用一种特殊的抽象树状结构表示代码的抽象语法结构

我们可以借助语法树工具AST Explorer (opens new window)直观的感受。

AST示例

上述示例表示了一个简单的HTML片段被转换成了一个特殊的树状结构。这个结构中的属性描述了HTML片段的关键信息。

# 模板编译内部流程

将模板编译成render函数可以分为两个步骤

  1. 将模板解析成AST
  2. 使用AST生成render函数

有些同学就比较疑惑,为什么中间要使用AST中转一下,直接将模板生成render函数多好,还省去中转的损耗的性能。实际通过模板语法直接转换为render函数的算法难度比较大,而AST本身就是一种成熟的方案,所以在框架的权衡下使用了AST方案。

在上一章节中,我们说过一种特殊的节点,静态节点。静态节点特性就是只渲染一次,所以为了性能优化,在生成AST之后,生成render函数之前,需要遍历AST,给静态节点增加一个标记,以便后续虚拟DOM处理时,不会重复渲染。

所以,在 Vue 中,模板编译成render函数分为三部分

  1. 解析器:将模板解析成AST
  2. 优化器:遍历AST标记静态节点
  3. 代码生成器:使用AST生成render函数

这三个阶段在源码中分别对应三个模块,下面给出三个模块的源代码在源码中的路径:

  1. 解析器——源码路径:src/compiler/parser/index.js
  2. 优化器——源码路径:src/compiler/optimizer.js
  3. 代码生成器——源码路径:src/compiler/codegen/index.js

流程图如下:

模板编译内部流程