前言
安装 npm install @vue/cli -g
构建项目 vue create vue3-compiler
用vite安装vue3项目
1 | npm i -g create-vite-app |
vue3一样需要把我们写的template最终变成render方法,看一下vue3的转换器。
编译过程
- 先将模板进行分析 生成对应的
ast树
(对象来描述语法); - 做转化流程 transform -> 对动态节点做一些标记 指令、插槽、事件、属性… patchFlag
- 代码生成 codegen -> 生成最终的代码
Block的概念 -> Block Tree
- diff算法的特点是递归遍历,每次比较同一层,比完自己比儿子、孙子…性能比较差,不停的递归,之前写的都是全量比对,所有的属性、方法都要比对。
- block的作用就是收集动态节点(它下面所有的);将树的递归拍平成了一个数组,以前要diff就要diff【children】 children下的children,现在只要diff【dynamicChildren】
- 在
createVNode
的时候就会判断这个节点是否是动态的,是的话就让外层的block收集起来 - 目的是为了diff的时候只diff动态的节点
举例:
1】
1 | <div></div> |
vue3里面可以有多个跟节点,编译会生成_Fragment包裹;
2】
添加动态节点
1 | <div>{{name}}</div> |
编译后:
1 | import { toDisplayString as _toDisplayString, createVNode as _createVNode, Fragment as _Fragment, openBlock as _openBlock, createBlock as _createBlock } from "vue" |
生成的ast树:
block的作用就是收集动态节点
3】
1 | <div> |
1 | block -> div 父亲更新 会找到dynamicChildren => 子的block和动态节点 |
编译后:
1 | import { createVNode as _createVNode, toDisplayString as _toDisplayString, Fragment as _Fragment, openBlock as _openBlock, createBlock as _createBlock, createCommentVNode as _createCommentVNode } from "vue" |
可以看到key从 0->1 需要全量比对
如果会影响dom结构的,都会被标记成block节点: v-if v-else
动态内容自己和父节点都会标记为block,父亲会收集儿子的block -> Block Tree;
4】
1 | <div> |
1 | block -> div |
v-for 序列不稳定,改变结构的也要封装到block中,期望的更新方式是拿以前的和现在的做对比,靶向更新,如果前后节点不一致,只能全量比对
两个儿子(children)的全量比对,全量diff就是用之前的递归方法去比
Block Tree做的就是保证需要更新的时候能知道哪些节点需要更新
patchFlag
描述不同的动态节点,以此来做相对应的比对
源码:packages/shared/src/patchFlags
render方法
源码:packages/runtime-core/src/renderer