vlambda博客
学习文章列表

Vue 编译器源码分析 - 开篇第一章

前几天看到知乎上有人质疑尤雨溪不懂编译原理。这说的啥话,咱也听不懂啊!索性就把Vue 编译器部分代码从头到尾分析一遍,首先声明写文章与知乎事故无关,编译器源码分析纯粹个人喜好。

写过 Vue 代码的小伙伴都知道,Vue在绝大多数情况下推荐使用模板来创建HTML。 那为什么不直接写HTML?那是因为Vue想动态的响应数据的变化,从而根据数据的 change 改变视图。另外如果先写模板在转成 HTML 那么UI 就拥有灵活的复用性了。 

在深入了解模板转化成HTML之前,了解一些浏览器的工作原理是很重要的。以下面这段 HTML 为例:

<div> <h1>My title</h1> Some text content <!-- TODO: Add tagline --></div>

当浏览器读到这些代码时,它会建立一个"DOM 节点"树来保持追踪所有内容,如同你会画一张家谱树来追踪家庭成员的发展一样。

上述 HTML 对应的 DOM 节点树如下图所示:

每个元素都是一个节点。每段文字也是一个节点。甚至注释也都是节点。一个节点就是页面的一个部分。就像家谱树一样,每个节点也都可以有子节点 。

高效地更新所有这些节点会是比较困难的,不过所幸你不必手动完成这个工作。你只需要告诉 Vue 你希望页面上的 HTML 是什么,这可以是在一个模板里:

<h1>{{ message }}</h1>

或者一个渲染函数里:

render: function (createElement) {  return createElement('h1'this.message)}

在这两种情况下,Vue 都会自动保持页面的更新,即便 message 发生了改变,怎么做到的 ?这个过程其实就是Vue 通过建立一个Virtual DOM 来追踪自己要如何改变真实 DOM。


而接下来我们就是要一起去探索Vue 如何把模板映射成一个Virtual DOM ,是如何去改变真实的DOM。

Vue编译器运作机原理图:


宏观的理论上讲讲Vue编译器分成 parseoptimize 与 generate 三个阶段,最终需要得到 render function。

parse

parse 会用正则等方式解析 template 模板中的指令、class、style等数据,形成AST。

optimize

optimize 的主要作用是标记 static 静态节点,这是 Vue 在编译过程中的一处优化,后面当 update 更新界面时,会有一个 patch 的过程, diff 算法会直接跳过静态节点,从而减少了比较的过程,优化了 patch 的性能。

generate

generate 是将 AST 转化成 render function 字符串的过程,得到结果是 render 的字符串以及 staticRenderFns 字符串。

在经历过 parseoptimize 与 generate 这三个阶段以后,组件中就会存在渲染 VNode 所需的 render function 了。