vue3源码概述
本文选自vue3源码解析第二章
详情见github
本节开始正式进入vue3
源码的分析,有了前一节的知识的,我们直接使用demo里面的例子作为用例
源码结构
packages
目录下面的包的作用见下表
包目录 | 作用 |
---|---|
compiler-core | 先忽略 |
compiler-dom | 先忽略 |
compiler-sfc | 先忽略 |
compiler-ssr | 先忽略 |
dts-test | 直接忽略 |
reactivity | 响应式相关代码,比如ref 等都在这里 |
reactivity-transform | 先忽略 |
runtime-core | 渲染的核心代码(于平台无关) |
runtime-dom | dom渲染有关代码 |
runtime-test | 直接忽略 |
server-renderer | 先忽略 |
sfc-playground | 直接忽略 |
shared | 公共工具函数 |
size-check | 直接忽略 |
template-explorer | 直接忽略 |
vue | 包导出 |
vue-compat | 直接忽略 |
是不是感觉代码很多,别急,很多包实际上在代码运行的时候是用不到的,比如先忽略的包很多都是编译阶段使用的包在运行阶段是不会起任何作用的,这个以后在说。
核心包
对于非ssr
的项目而言,核心的包只有以下四个
包目录 | 作用 |
---|---|
reactivity | 响应式相关代码,比如ref 等都在这里 |
runtime-core | 渲染的核心代码(于平台无关) |
runtime-dom | dom渲染有关代码 |
shared | 公共工具函数 |
基本数据结构
基本数据结构是在运行中常用的数据结构。
component
常说的组件是import HelloWorld from './helloworld.vue'
中的HelloWorld
。在使用webpack
和vue-loader
时,这里导入的组件会被vue-loader
自动处理。对于Options API
的组件来讲,这里以demo中的App.vue
来讲,具有以下结构
对于composite setup
的组件来讲,具有一下结构
总结起来就是component
是经过编译器处理后得到的产物。具有一定结构
app
一个app
是createApp函数的返回值,第一个参数是根组件。第二个参数可选,它是要传递给根组件的 props。根组件就是上面所说的component
app具有以下结构
component instance
component instance
表示在运行过程中创建好的component
,和component
的区分是component
只是编译后的一个对象,这个对象不需要vue
的创建就可以单独存在,而component instance
是vue
在渲染过程中创建的内部对象,用以渲染的用途
component instance
具有以下结构
vnode
这个不多讲官网文档里面有。vnode
是渲染算法的核心结构。type=component
的vnode
具有以下结构
vnode还有其他很多种结构这里不列出
container
app.mount
函数的第一个参数是container
,类型为Element
依赖图
对于type=component
的vnode
来讲,以上数据结构具有如下的关系
图中的
container
相关依赖仅为根组件具有,其他component
不具有
运行概述
首次渲染
火焰图
从图中可以看出第一次渲染主要分为两步
- 创建
app
对象 - 手动调用对象的
mount
方法
mount
函数是第一次渲染的调用的函数,从图中可以看到mount
函数会调用render
函数,render
函数的核心是patch
函数。
这里先给出结论,vue
的渲染实际上是递归调用patch
函数进行深度优先遍历
直到完成渲染。
非首次渲染
图1左边部分位于图2的红色框区域
从图中可以看到非首次渲染也分为两部分
- 触发更新
- 执行更新
执行更新的函数调用时处于一个微任务调用栈里面(图2的run MircoTasks
)。
之后调用的核心函数是componentUpdateFn
,这个函数在之后也会调用patch
方法去递归遍历进行渲染
总结
vue3
的渲染无论是首次还是非首次核心都是递归调用patch
算法进行深度优先遍历进行渲染