Vue3模板编译原理简要梳理 您所在的位置:网站首页 vue是如何解析模板的 Vue3模板编译原理简要梳理

Vue3模板编译原理简要梳理

2023-11-25 02:16| 来源: 网络整理| 查看: 265

这篇博客针对Vue3的编译模块进行原理上的简要梳理,不做源码层面上的分析

一、Vue3的编译与运行时

熟悉Vue框架的开发者应该都知道,使用Vue项目进行开发时,是分为模板编译和运行时2大阶段的。也许你会这样理解,当使用sfc单文件组件的模式进行开发,需要将.vue文件解析为浏览器能识别的.js和.css文件,这就是模板编译,这种理解是不正确的,这里面存在2步操作,先进行文件编译,再进行模板编译。

要正确理解模板编译与运行时,则需要了解这2个模块之间的关系,模板编译的最终产物是生成render渲染函数,运行时则是直接运行这个render函数,生成dom节点。如下图:

Vue3编译与运行时.png

compiler-dom 针对模板字符串进行编译 compiler-sfc 针对.vue文件进行编译 compiler-ssr 针对服务端渲染进行编译 compiler-core 是3上述3个模块的公用模块,是编译核心 1. 为什么要将模板编译和运行时分离?

为什么要将模板编译与运行时进行分离成2个完全独立的阶段?要理解这个问题,则需要明确模板编译是否有存在的必要性。

模板编译的目的是生成render函数,如果在开发时,我们直接编写这个render函数,那么模板编译将没有存在的必要。一个非必选的模块,自然是可以与运行时进行分离的。

2. 有编译模块和没有编译模块的Vue项目有什么不同?

Vue的打包代码有带模板编译版本和不带模板编译版本的包。带模板编译的包既可以实现模板编译,也包含运行时,是一个完整包体,那么为什么还需要不带模板编译的包?

我们已经知道,运行时和模板编译是分离的2个阶段,使用Vite等构建工具构建Vue项目时,会提前在本地进行了模板编译,但这并不代表不能在运行时去编译模板,比如直接使用标签引入vue.js,并编译一段模板字符串。但在运行时编译模板,会存在一个致命的缺陷,那就是性能问题,编译模板是很消耗性能和时间的,因此在注重页面交互体验的今天,如果能够将这些高消耗的工作预先完成,将能极大的提升用户体验。

二、模板编译模块

模板编译已经有一些概念上的简要介绍,接下来简要介绍下模板编译的原理。

模板编译一共分为3个阶段,分别如下:

parse

将一个模板字符串作为输入进行解析,这个字符串需要满足XML的数据格式,最终将会生成一棵AST抽象语法树,这棵AST抽象语法树本质就是一棵单根节点的多叉树。

transfrom

遍历parse阶段生成的AST树上的节点并进行转换。

generate

以transfrom阶段转换后的AST树为基础,针对不同节点的类型生成对应的代码字符串,最终生成一个完整的render函数。

1. parse

上面简要介绍了parse阶段,主要是针对模板字符串进行解析,生成AST抽象语法树。那么这棵树到底是怎样的呢?实际上是如下结构:

AST解析树结构.png

树的节点主要分为以下4种:

Inteprolation

Inteprolation是插值节点,解析模板插值语法,默认为{{ }}包含的内容

Comment

Comment是注释节点,解析注释语法,额外会将错误的模板和特定的模板解析为注释节点。

类似 会解析为注释节点,但这并不是错误模板。 会解析为注释节点,这是一个错误模板。

Text

Text是文本节点,解析文本语法。

Element

Element是元素节点,所有使用标签的都是Element节点,比如原生的 元素以及可能存在的自定义 元素。

这一步是针对XML格式的字符串数据格式进行解析,只要这个模板字符串是满足格式的输入,不管实际的数据是否存在,都是合法的,都能生成一棵AST抽象语法树。因为这是编译阶段,实际上的数据空值问题,需要在运行时才能暴露出来。

元素节点又分为以下四种:

Element - 原生的元素节点,如, Component - 组件节点,非另外3种节点 Slot - 插槽节点,针对节点 Template - 模板节点,针对节点

每个元素节点,都可以有属性,所以又存在2类属性节点:

Attribute - 属性节点 Directive - 指令节点,针对v-xxx语法以及@,:等指令的简写语法

当一个正确的模板被解析完成后,就能生成一棵如上图示中的抽象语法树,只有元素节点才能存在子节点,因为只有元素节点才有标签。

2. transfrom

当在parse阶段生成一棵AST抽象语法树后,这才只是第一步完成,且这一步只是针对模板的简要解析,无法转换为最终的dom树,因为有些特殊指令可能生成多个元素节点或者不生成节点,比如v-for和v-if。

parse阶段生成的AST语法树是针对模板语法的解析,不具备一些指令功能上的扩展。比如下面示例:

在parse阶段针对上面示例进行解析,只能解析出2个 元素节点,一个有指令节点,一个没有指令节点。无法凸显元素2节点v-for指令的作用。因此在transform阶段,需要对这些带有特殊指令的节点进行节点变换,凸显其对应指令的能力。简要图示如下:

transfrom原理.png

假如一个元素节点存在v-if指令,则会被转换为IfNode节点。上述图示不是完整的节点关系对应图,只是作为一个原理参考图。

3. generate

在transfrom阶段将AST抽象语法树上的节点进行变换完成之后,便可以针对这棵AST树生成对应的render函数,简单来说就是根据不同类型的节点,以及节点上可能存在的参数,生成渲染函数。图示如下:

generate原理.png

三、总结

模板编译的原理总结如上,相对而言是一个简述,避免代码层面的谈及也是因为除了在parse阶段逻辑较为清晰明了,在transfrom阶段有太多针对指令的处理,且模板编译的目的就是为了生成一个合理的render函数,本质上就是字符串的拼接,并没有太多的关注点。

不是很推荐去细读这块的源码,不过可以使用一些工具,如Vue Template Explore去直接看模板编译的render函数,间接的理解指令的作用。

虽然这块源码很复杂,但其中也有一个点值得注意,那就是静态提升。是否使用静态提升来进行优化,本质上是在模板编译阶段就决定来下了的,这块小点是值得单独注意的。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有