vue3的学习已经有一段时间了,本着奔浪不奔就可能变成后浪的态度,学习梳理了下vue3的编译,基于vue3的整个编译源码的学习,准备把编译源码按照编译过程分三部分记录学习下来,同各位奔浪一块儿奔跑.....html
一、目录结构前端
上面是整个代码的目录结构以及相关文件的主要做用,与模板编译相关的核心代码是compiler-core 中的整个目录,vue3源码链接奉上:github.com/vuejs/vue-n…vue
二、编译入口
/vue/src/index.tsgit
在完整版的 index.js
中,调用了 registerRuntimeCompiler
将 compile
注入编译方法,即为模板编译的入口,固然其中还有一些其余的判断,有兴趣的能够进入继续查看源码github
vue2编译web
vue3编译babel
整个编译流程其实主要分为三部分:整个编译过程跟vue2的编译的过程有markdown
template模板字符串 ----》编译为最基础的AST ----> transform基础AST增长patchflag等熟悉 ----》 generate基于AST生成render函数数据结构
<div name="test">
<!-- 这是注释 -->
<p>{{ test }}</p>
一个文本节点
<div>good job</div>
</div>
复制代码
vue2编译后结果:函数
function render() {
with(this) {
return _c('div', {
attrs: {
"name": "test"
}
}, [_c('p', [_v(_s(test))]), _v("\n 一个文本节点\n "), _c('div', [_v(
"good job")])])
}
}
复制代码
vue3编译后结果:
import {
createCommentVNode as _createCommentVNode,
toDisplayString as _toDisplayString,
createVNode as _createVNode,
createTextVNode as _createTextVNode,
openBlock as _openBlock,
createBlock as _createBlock
} from "vue"
const _hoisted_1 = {
name: "test"
}
const _hoisted_2 = /*#__PURE__*/ _createTextVNode(" 一个文本节点 ")
const _hoisted_3 = /*#__PURE__*/ _createVNode("div", null, "good job", -1 /* HOISTED */ )
export function render(_ctx, _cache, $props, $setup, $data, $options) {
return (_openBlock(), _createBlock("div", _hoisted_1, [
_createCommentVNode(" 这是注释 "),
_createVNode("p", null, _toDisplayString(_ctx.test), 1 /* TEXT */ ),
_hoisted_2,
_hoisted_3
]))
}
复制代码
经过对比发现最终都返回render函数,可是render函数的结构和样式上有了很大的差异,同时有了特殊的含义注释,在接下来的过程当中咱们会一点点接口神秘面纱....
源码的第一部分 baseParse主要的做用就是将 template模板字符串编译为基础AST树,可是咱们能够思考下他说怎么转换生成的呢?
(1)、类比前端模板引擎
(2)、类比babel编译过程
(3)、vue3解析
之因此用前端模板和bable的编译过程来类别vue3的编译,其实他们是有不少共性的,
好比:前端模板编译
const data = {
'title':'模板标题',
'content':'模板内容'
}
const temp = '
<div>{{d.title}}</div>
<div>{{d.content}}</div>
复制代码
这种 data + temp---》html的 很容易想到基于正则的进行匹配替换。
好比:bable编译
function test(){
const a = b
}
复制代码
这个函数字符串如何进行词法解析 、预发解析呢?其实也是基于正则不断的对字符串进行选择、截取、 匹配.....直到最有一个字符完成,function等关键字等同于div等标签的关键字,函数的"{"(开始左括号) 和 ”}“(结束右括号) 等同于div标签的"
vue3中将template--->baseParse解析为AST的过程也是同样的:
四、父子关系
单纯的正则匹配和解析只是获取了标签自己的属性、特性等数据,可是template自己的标签是有父子层级关系的,标签与标签直接的关系怎么来维护呢?了解过webkit渲染原理的应该很容易想到,栈:一个先进后出的数据结构
//解析过程当中:
<div name="test">
<!-- 这是注释 -->
<p>{{ test }}</p>
一个文本节点
<div>good job</div>
</div>
复制代码
vue3的第一部分实际上是不断将模板字符串经过正则去解析、截取、匹配特殊数据和属性......过程,同时在解析中用栈的形式维护保存正在解析的标签