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 源码的主体结构及初始化的流程,水平及时间有限,本文没有做特别详细的讲解,如有任何问题或建议,欢迎留言讨论!👏🏻👏🏻👏🏻


喜欢的话点个赞吧!

相关文章
|
7天前
|
JavaScript 前端开发 开发者
Vue 3中的Proxy
【10月更文挑战第23天】Vue 3中的`Proxy`为响应式系统带来了更强大、更灵活的功能,解决了Vue 2中响应式系统的一些局限性,同时在性能方面也有一定的提升,为开发者提供了更好的开发体验和性能保障。
20 7
|
8天前
|
前端开发 数据库
芋道框架审批流如何实现(Cloud+Vue3)
芋道框架审批流如何实现(Cloud+Vue3)
28 3
|
7天前
|
JavaScript 数据管理 Java
在 Vue 3 中使用 Proxy 实现数据双向绑定的性能如何?
【10月更文挑战第23天】Vue 3中使用Proxy实现数据双向绑定在多个方面都带来了性能的提升,从更高效的响应式追踪、更好的初始化性能、对数组操作的优化到更优的内存管理等,使得Vue 3在处理复杂的应用场景和大量数据时能够更加高效和稳定地运行。
26 1
|
7天前
|
JavaScript 开发者
在 Vue 3 中使用 Proxy 实现数据的双向绑定
【10月更文挑战第23天】Vue 3利用 `Proxy` 实现了数据的双向绑定,无论是使用内置的指令如 `v-model`,还是通过自定义事件或自定义指令,都能够方便地实现数据与视图之间的双向交互,满足不同场景下的开发需求。
26 1
|
10天前
|
前端开发 JavaScript
简记 Vue3(一)—— setup、ref、reactive、toRefs、toRef
简记 Vue3(一)—— setup、ref、reactive、toRefs、toRef
|
11天前
|
数据采集 监控 JavaScript
在 Vue 项目中使用预渲染技术
【10月更文挑战第23天】在 Vue 项目中使用预渲染技术是提升 SEO 效果的有效途径之一。通过选择合适的预渲染工具,正确配置和运行预渲染操作,结合其他 SEO 策略,可以实现更好的搜索引擎优化效果。同时,需要不断地监控和优化预渲染效果,以适应不断变化的搜索引擎环境和用户需求。
|
4天前
|
JavaScript
Vue基础知识总结 4:vue组件化开发
Vue基础知识总结 4:vue组件化开发
|
4天前
|
存储 JavaScript
Vue 状态管理工具vuex
Vue 状态管理工具vuex
|
11天前
|
缓存 JavaScript 搜索推荐
Vue SSR(服务端渲染)预渲染的工作原理
【10月更文挑战第23天】Vue SSR 预渲染通过一系列复杂的步骤和机制,实现了在服务器端生成静态 HTML 页面的目标。它为提升 Vue 应用的性能、SEO 效果以及用户体验提供了有力的支持。随着技术的不断发展,Vue SSR 预渲染技术也将不断完善和创新,以适应不断变化的互联网环境和用户需求。
30 9
|
10天前
|
缓存 JavaScript UED
Vue 中实现组件的懒加载
【10月更文挑战第23天】组件的懒加载是 Vue 应用中提高性能的重要手段之一。通过合理运用动态导入、路由配置等方式,可以实现组件的按需加载,减少资源浪费,提高应用的响应速度和用户体验。在实际应用中,需要根据具体情况选择合适的懒加载方式,并结合性能优化的其他措施,以打造更高效、更优质的 Vue 应用。