前言:本文探讨Vue3
框架中createApp
函数与mount
方法的大致工作机制。首先介绍深入源码的工具和方式,而后介绍vue
源码项目架构,最后详述vue
创建实例应用的大致流程。
一、前序
1.1 调试准备工作
通过浏览器debugger调试的第一视角,了解代码的执行机制:
- vue3源码地址:https://github.com/vuejs/core,
git clone
到本地,然后执行下面命令即可
pnpm i
pnpm dev
Live Server
:vscode下这个插件,目的是运行html文件并提供热更新作用
- 会使用浏览器debugger功能,比较常用的有以下几点
- 定位源码区域,可以自行设置断点
- 变量区域,可以了解执行区域函数里面的具体变量值
- 调用栈,可以回溯调用
- 命令调试
F8:下一个断点处
F9:下一步如果是调用函数,则进入函数内
F10:下一步如果是调用函数,则跳过函数
F11:和F9作用几乎一致,执行异步代码会进入,F9不会
Shift+F11:跳出当前函数
源码结构
项目结构为monorepo
架构方式,更加合理组织项目核心模块
- compiler模块:编译
- compiler-core:核心编译模块
- compiler-dom:依赖compiler-core,处理template标签的,将template内容编译成render函数
- compiler-sfc:解析vue文件
- compiler-ssr:服务端编译相关
- reactivity模块:响应式核心。(通过子包的形式,可以脱离vue环境,单独使用)
- runtime模块:运行时
- server-renderer:服务端渲染相关
- temaplate-explorer:查看模板编译结果
- shared:公共方法
- vue:框架集成入口
二、createApp
vue选项式api创建一个应用
Vue通过createApp
初始化一个Vue实例,然后通过实例方法mount
挂载组件。
通过debugger可以走到该部分代码
ensureRenderer
F9进入ensureRenderer
函数内部:
其主要功能就是核心渲染相关,负责根据当前运行环境创建一个适合的渲染器:
- 39行和46行代码:
ensureRenderer
方法只初始化一次 - 60行和68行也就是
ensureRenderer
方法向外暴露出去的接口(render
和createApp
)
createAppAPI(ensureRenderer所暴露出来的)
根据ensureRenderer
所返回的渲染器执行createAppAPI
方法创建一个实例,也就是创建Vue实例对象的核心逻辑所在。
F9进入createAppAPI
函数内部:
- 参数部分:
rootComponent
:也就是我们所写的选项式API的“选项”
为什么data属性是一个函数而不是一个对象?
- 避免对象数据污染:如果是对象的话,只是单纯的引用值(通用同一个内存地址,一处修改,其他所有敌方都会改变),如果是函数的话,则是原始值
这部分的data如何响应化?
- 215行代码:
context
是用于记录组件的属性 - 238行代码到384行代码:定义了我们常见的一些
API
mount方法的重写
经过ensureRenderer
方法和createApp
方法所得到的实例对象app
,还会经过一次mount的重写,这是为什么呢?
通过解构出上述返回的
app
对象中的mount
,重写了app.mount
方法,这个和不同类型的渲染有关,比如说服务端渲染可能需要不同的挂载逻辑。通过重写mount
,可以提供一个统一的API接口,这一点也体现了Vue的灵活所在。
- 77行到103行代码:根据传进的需要挂载的
DOM
id
值,读取DOM
处理前的内容将其编译为供后续生成DOM
需要的component
对象
深入应用实例mount方法
mount
内部,了解一下mount
挂载全过程:
- 310行代码:实例挂载只能挂载一次
- 319行代码:根据“选项” 生成虚拟节点(
vnode
),同时将上述的context
赋值给虚拟节点,至此,我们常说的虚拟节点到渲染真是节点的虚拟节点部分完成了
响应式也在该部分内部完成
- _createVNode
- createBaseVNode:这里有了vnode,但是没有实例(app._instance)
- 343行代码:
if
条件里面是服务端渲染相关,暂不考虑,走到else
的真实DOM
渲染逻辑,也就是render
逻辑 - 346行代码:渲染
- 349行代码:最后记录挂载的容器信息:
_container
render
mount
方法内部会调用render
函数来将传入的模板(template
或者render
函数构建)生成虚拟DOM
,然后通过对虚拟DOM
的处理将其转换成实际的DOM
结构并插入到页面中
F9
走进render
函数内部:
- 参数部分
- vnode:待渲染的虚拟节点
- container:页面挂载容器
- namespace
- 2362行代码:转换的核心逻辑,其主要逻辑就是对两个虚拟节点进行
diff
比较,比较出差异部分再按需更新真实DOM
节点。
挂载前后对比
以下就是通过vue渲染前后的对比页面
评论区