Vue3源码的主体结构及初始化流程

简介: Vue3源码的主体结构及初始化流程

网络异常,图片无法展示
|


「这是我参与2022首次更文挑战的第36天,活动详情查看:2022首次更文挑战


主体架构


代码组织


  • TypeScript 代码编写
  • rollup 打包
  • jest 单元测试
  • eslint 代码检查
  • prettier 代码格式化


目录结构


  • packages 代码包,里面主要分为以下三个大模块:
  • compiler 编译相关
  • reactivity 响应式
  • runtime 运行时
  • scripts 脚本


上文Vue 源码学习开篇!中我们使用 pnpm dev进行了开发环境打包,并且添加了 --sourcemap 配置,这个命令会执行 scripts/dev.js 文件进行打包,接下来我们看一下打包这个动作 vue 到底都做了什么,然后基于它去理解其他的打包命令就可以了。


网络异常,图片无法展示
|


上图我对 scripts/dev.js 文件进行了逐行注释,大体逻辑是基于命令获取各种打包配置,然后利用 execa 执行打包脚本,并传入打包配置。


读懂了 pnpm dev 的逻辑,其他的打包命令基本就大同小异了。


模块依赖关系


目录结构部分提到 packages 代码包中主要分为以下三个大模块:


  • compiler 编译相关
  • reactivity 响应式
  • runtime 运行时


所以这里我们讲主体的依赖关系就是下图所示:

网络异常,图片无法展示
|


上面是一个简单的主体依赖关系图,这里我们大致说一下一个 Vue 页面的运行,解释一下这三个模块是如何协作。


  1. 当我们创建一个 Vue 页面的时候,会有一个 templete 以及响应对象。
  2. 首先 compiler 会编辑 templete 生成 render 函数,然后 reactivity 会初始化响应对象,接着 runtime 中的 renderer 会调用 render 函数返回 VNode,要注意 render 函数中可能会引用响应对象中的数据。renderer 拿到 VNode 调用 mount 函数使用 VNode 创建 Web页面。
  3. 接下来,当我们的响应对象发生变化的时候,如果 render 函数中引用了对应的数据,renderder 则会再次调用 render 函数获取新的 VNode,然后对比新老 VNode, 给到 path 函数,然后根据需要更新 Web页面。


初始化流程


在上文的 todomvc 例子中(文件在packages/vue/examples/composition/todumvc.html),初始化的逻辑主要分为两步,调用 createApp 创建实例,然后调用实例上的 mount 方法进行挂载。


那接下来,我们提出两个问题,然后带着问题去读源码。


  1. 如何创建实例?创建的实例是什么样的?
  2. 挂载的过程是什么样的?


实例创建


我们首先还是使用命令 pnpm serve 启动本地服务,然后显示如下界面说明服务启动成功。


网络异常,图片无法展示
|


打开对应的本地服务地址


网络异常,图片无法展示
|


接下来打开 packages/vue/examples/composition/todomvc 目录,进入 todomvc 示例页面。


网络异常,图片无法展示
|


然后打开控制台,源代码面板,打开 todomvc 文件,在第 93 行打上断点(这里调试的过程后续不做赘述)。


获取 app 实例


然后我们可以找到 createApp 方法是在 packages/runtime-dom/src/index.ts 66行 中定义的。


该方法会调用 ensureRenderer 方法获取一个 renderer 实例,然后调用该实例的 createApp 方法,并将参数传入,最后获取一个 app 实例。


const app = ensureRenderer().createApp(...args) (67行)


然后会从 app 实例中解构出 mount 方法,并对 mount 方法进行扩展。(74行) 最后返回 app 实例(111行)。 到了这一步,我们已经浅显的知道了 createApp 的过程,但是真正的内容还没有看到,比如 ensureRenderer 方法做了什么,返回的 renderer 实例是什么样的,它的 createApp 又做了什么呢?


ensureRenderer


接下来我们去查找 ensureRenderer 的定义,发现就在当前文件的 42 行进行定义,而返回的 renderer 则是通过 createRenderer 方法创建,那接下来我们再去看一下 createRenderer 这个方法。


createRenderer


createRenderer 是在 @vue/runtime-core 中引入的。


再接下来,我们在 packages/runtime-core/src/renderer.ts 文件中找到了该方法的定义(290行)。


export function createRenderer<
  HostNode = RendererNode,
  HostElement = RendererElement
>(options: RendererOptions<HostNode, HostElement>) {
  return baseCreateRenderer<HostNode, HostElement>(options)
}
复制代码


该方法又返回了调用 baseCreateRenderer 方法的结果。


baseCreateRenderer


createRenderer 方法下面就是 baseCreateRenderer 方法的定义,从 309 行一直到 2341 行。


最后返回一个对象


return {
  render,
  hydrate,
  createApp: createAppAPI(render, hydrate)
}
复制代码


render 函数就是将传入 vnode 转为 真实 dom 并挂载到宿主对象上,如果 vnode 对应 dom 已经存在,则会走 path 新老 vdom 逻辑。


hydrate 这里我们略过,因为我还没搞懂 😅,这里的结果为 undefined


createApp 则是调用 createAppAPI 之后的返回值。


那么接下来就要看一下 createAppAPI 做了什么了。


createAppAPI


createAppAPI 方法在 runtime-core/src/apiCreateApp.ts 177行 定义。


该方法返回一个函数 createAppcreateApp 函数会在内部创建一个包含 use、mixin、component、directive、mount、unmount、provide 方法的对象并返回。


至此,我们了解到 createApp 方法是在 runtime-dom/src/index.ts 66 行 定义,返回的是一个 app 实例。而这个 app 实例 是调用

ensureRenderer().createApp(...args) 得到的,其中 ensureRenderer 会通过一系列调用返回一个包含 createApp 方法的对象。


网络异常,图片无法展示
|


挂载


挂载相对就简单很多了,其实就是调用 createApp 返回的 app 实例mount 方法,该方法会判断当前 app 实例 是否已挂载,如果没有挂载,则会创建对应的 vnode,然后通过 render 方法将 vnode 挂载到其宿主元素上,否则什么也不做。


本文主要介绍了 Vue3 源码的主体结构及初始化的流程,水平及时间有限,本文没有做特别详细的讲解,如有任何问题或建议,欢迎留言讨论!👏🏻👏🏻👏🏻


喜欢的话点个赞吧!

相关文章
|
4月前
|
JavaScript 前端开发 安全
Vue 3
Vue 3以组合式API、Proxy响应式系统和全面TypeScript支持,重构前端开发范式。性能优化与生态协同并进,兼顾易用性与工程化,引领Web开发迈向高效、可维护的新纪元。(238字)
772 139
|
4月前
|
缓存 JavaScript 算法
Vue 3性能优化
Vue 3 通过 Proxy 和编译优化提升性能,但仍需遵循最佳实践。合理使用 v-if、key、computed,避免深度监听,利用懒加载与虚拟列表,结合打包优化,方可充分发挥其性能优势。(239字)
396 1
|
5月前
|
开发工具 iOS开发 MacOS
基于Vite7.1+Vue3+Pinia3+ArcoDesign网页版webos后台模板
最新版研发vite7+vue3.5+pinia3+arco-design仿macos/windows风格网页版OS系统Vite-Vue3-WebOS。
629 11
|
4月前
|
JavaScript 安全
vue3使用ts传参教程
Vue 3结合TypeScript实现组件传参,提升类型安全与开发效率。涵盖Props、Emits、v-model双向绑定及useAttrs透传属性,建议明确声明类型,保障代码质量。
463 0
|
6月前
|
缓存 前端开发 大数据
虚拟列表在Vue3中的具体应用场景有哪些?
虚拟列表在 Vue3 中通过仅渲染可视区域内容,显著提升大数据列表性能,适用于 ERP 表格、聊天界面、社交媒体、阅读器、日历及树形结构等场景,结合 `vue-virtual-scroller` 等工具可实现高效滚动与交互体验。
656 1
|
5月前
|
JavaScript
Vue中如何实现兄弟组件之间的通信
在Vue中,兄弟组件可通过父组件中转、事件总线、Vuex/Pinia或provide/inject实现通信。小型项目推荐父组件中转或事件总线,大型项目建议使用Pinia等状态管理工具,确保数据流清晰可控,避免内存泄漏。
515 2
|
4月前
|
缓存 JavaScript
vue中的keep-alive问题(2)
vue中的keep-alive问题(2)
432 137
|
8月前
|
人工智能 JavaScript 算法
Vue 中 key 属性的深入解析:改变 key 导致组件销毁与重建
Vue 中 key 属性的深入解析:改变 key 导致组件销毁与重建
985 0
|
8月前
|
JavaScript UED
用组件懒加载优化Vue应用性能
用组件懒加载优化Vue应用性能
|
9月前
|
JavaScript 数据可视化 前端开发
基于 Vue 与 D3 的可拖拽拓扑图技术方案及应用案例解析
本文介绍了基于Vue和D3实现可拖拽拓扑图的技术方案与应用实例。通过Vue构建用户界面和交互逻辑,结合D3强大的数据可视化能力,实现了力导向布局、节点拖拽、交互事件等功能。文章详细讲解了数据模型设计、拖拽功能实现、组件封装及高级扩展(如节点类型定制、连接样式优化等),并提供了性能优化方案以应对大数据量场景。最终,展示了基础网络拓扑、实时更新拓扑等应用实例,为开发者提供了一套完整的实现思路和实践经验。
1280 78