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


喜欢的话点个赞吧!

相关文章
|
23天前
|
缓存 JavaScript UED
Vue3中v-model在处理自定义组件双向数据绑定时有哪些注意事项?
在使用`v-model`处理自定义组件双向数据绑定时,要仔细考虑各种因素,确保数据的准确传递和更新,同时提供良好的用户体验和代码可维护性。通过合理的设计和注意事项的遵循,能够更好地发挥`v-model`的优势,实现高效的双向数据绑定效果。
126 64
|
23天前
|
前端开发 JavaScript 测试技术
Vue3中v-model在处理自定义组件双向数据绑定时,如何避免循环引用?
Web 组件化是一种有效的开发方法,可以提高项目的质量、效率和可维护性。在实际项目中,要结合项目的具体情况,合理应用 Web 组件化的理念和技术,实现项目的成功实施和交付。通过不断地探索和实践,将 Web 组件化的优势充分发挥出来,为前端开发领域的发展做出贡献。
29 8
|
22天前
|
存储 JavaScript 数据管理
除了provide/inject,Vue3中还有哪些方式可以避免v-model的循环引用?
需要注意的是,在实际开发中,应根据具体的项目需求和组件结构来选择合适的方式来避免`v-model`的循环引用。同时,要综合考虑代码的可读性、可维护性和性能等因素,以确保系统的稳定和高效运行。
22 1
|
22天前
|
JavaScript
Vue3中使用provide/inject来避免v-model的循环引用
`provide`和`inject`是 Vue 3 中非常有用的特性,在处理一些复杂的组件间通信问题时,可以提供一种灵活的解决方案。通过合理使用它们,可以帮助我们更好地避免`v-model`的循环引用问题,提高代码的质量和可维护性。
33 1
|
23天前
|
JavaScript
在 Vue 3 中,如何使用 v-model 来处理自定义组件的双向数据绑定?
需要注意的是,在实际开发中,根据具体的业务需求和组件设计,可能需要对上述步骤进行适当的调整和优化,以确保双向数据绑定的正确性和稳定性。同时,深入理解 Vue 3 的响应式机制和组件通信原理,将有助于更好地运用 `v-model` 实现自定义组件的双向数据绑定。
|
27天前
|
JavaScript API 开发者
Vue是如何进行组件化的
Vue是如何进行组件化的
|
28天前
|
JavaScript 前端开发 开发者
vue 数据驱动视图
总之,Vue 数据驱动视图是一种先进的理念和技术,它为前端开发带来了巨大的便利和优势。通过理解和应用这一特性,开发者能够构建出更加动态、高效、用户体验良好的前端应用。在不断发展的前端领域中,数据驱动视图将继续发挥重要作用,推动着应用界面的不断创新和进化。
|
2天前
|
JavaScript 关系型数据库 MySQL
基于VUE的校园二手交易平台系统设计与实现毕业设计论文模板
基于Vue的校园二手交易平台是一款专为校园用户设计的在线交易系统,提供简洁高效、安全可靠的二手商品买卖环境。平台利用Vue框架的响应式数据绑定和组件化特性,实现用户友好的界面,方便商品浏览、发布与管理。该系统采用Node.js、MySQL及B/S架构,确保稳定性和多功能模块设计,涵盖管理员和用户功能模块,促进物品循环使用,降低开销,提升环保意识,助力绿色校园文化建设。
|
1月前
|
JavaScript 前端开发 开发者
vue学习第一章
欢迎来到我的博客!我是瑞雨溪,一名热爱前端的大一学生,专注于JavaScript与Vue,正向全栈进发。博客分享Vue学习心得、命令式与声明式编程对比、列表展示及计数器案例等。关注我,持续更新中!🎉🎉🎉
36 1
vue学习第一章
|
1月前
|
JavaScript 前端开发 索引
vue学习第三章
欢迎来到瑞雨溪的博客,一名热爱JavaScript与Vue的大一学生。本文介绍了Vue中的v-bind指令,包括基本使用、动态绑定class及style等,希望能为你的前端学习之路提供帮助。持续关注,更多精彩内容即将呈现!🎉🎉🎉
26 1
vue学习第三章
下一篇
DataWorks