vue-3.0 runtime-core 源码阅读指南

写在前面

最近又抽时间把 vue-next/runtime-core 的源码陆陆续续地看完了,期间整理了不少笔记,但都是碎片化的。原本是想整理一下,写成一篇文章分享出来的,可是感受最终的成果物只能是一篇篇幅巨长的解析文,就算我一行一行的把源码加上注释,其阅读体验也会不好,由于每一个人读代码的习惯不一样,思路不一样。正所谓抛砖引玉,因此,我觉的写一篇向导文做为这块砖应该是足够了,但愿能够帮助到想看源码但以为无从看起、无从下手的读者。vue

另外一方面,也算是给本身挖一个坑,由于这篇文章中涉及到的不少内容,三言两语确定是说不清的,这就意味着以后必需要写其余文章来填补这些空白。我会尽量的将高内聚的模块整理到一块儿,而后再分享出来,尽可能避免陷入罗列代码的境地,从而提升文章质量吧。node

阅读笔记我托管在语雀上,不嫌乱的也能够看这里react

准备工做

工欲善其事,必先利其器,要看源码,拿写字板来看确定是不行的(固然也不排除牛人)。你所须要的就是一个支持代码跳转的编辑器便可,我用的是 VSCode,固然了,若是你用 VIMSublime 也是能够的。typescript

另外还需一些储备知识:canvas

  • 因为是阅读 vue-next 的代码,而且是 pre-alpha 的版本,这就要求你对以前 vue 有必定的了解,若是是第一次接触,我觉的阅读源码的意义也不是很大
  • 须要熟练掌握 debug 的基础技巧和流程,经过 debug 的方式来看代码有两个好处小程序

    • debug 过程有清晰地调用栈记录
    • 各类做用域下的变量一目了然
  • 须要对 typescript 有必定掌握程度,最起码给知道 interfaceenum 等概念

如何阅读

通常有三种途径:api

  • 直接看
  • 经过单元测试的可执行代码
  • 本身编写的可执行代码

这里推荐第二种方式,由于单元测试是官方团队维护的,质量确定有保证,二来单元测试通常都很简单,同时带有注释,这有利于咱们理解代码。数组

因为 vue-next 使用 jest 进行单元测试,在 vscode 中安装 Jest 插件便可,它支持行内 debug lens 快捷入口,方便直接对某条单元测试进行 debug缓存

不过要注意配置一个自定义选项:数据结构

"jest.debugCodeLens.showWhenTestStateIn": [
    "fail",
    "unknown",
    "pass", // 注意这里
]

这里的 "pass" 表明即便单元测试经过,也会在上方显示 debug lens,默认状况下,单元测试用例经过的话,这个 debug lens 标识不会显示。

模块职能概括

runtime-core 目录下有多个文件,我暂且把每一个文件都当作一个子模块来看待。vue 的代码质量仍是挺好的,模块与模块之间的耦合性都不是特别高,正由于如此,基本上每一个模块都有本身单独对应的单元测试文件。

我在看的时候,基本上就是挨个看这些模块的单元测试,而后调试过程当中,会主动的进行一些代码跳转,去看一下具体的实现细节。下面把当前最新代码下该文件目录下的全部模块的职能进行一些总结和概括。

有一些较独立的模块我尚未看完,可是不影响总体的源码阅读进程,往后对这些独立模块进行单独研究时,才回来补充这些 todo 就行了。

公共 api 相关

实现公共 api 的模块均是以 apixxx 这样的格式来命名的,以下:

  • apiApp.ts: 有 3 个比较重要的接口须要看一下,AppAppConfigAppContext,若是对于 vue2 比较熟悉的话,会很容易理解。createApp 是一个工厂方法,返回一个符合 App 接口约束的对象,其内部方法会与一个符合 AppContext 接口约束的对象进行交互。
  • apiCreateComponent.ts: 这个文件内部包含多个对于 createComponent 函数签名的重载声明,其存在目的应该是为了帮助 ts 提供更好的类型推断以提高开发体验。
  • apiInject.ts: 组件依赖注入 feature 的实现逻辑,实现方式很简单,直接与 component 文件中暴露的 currentInstance 变量进行交互,实现继承、赋值、取值等逻辑
  • apiLifecycle.ts: 新的组件声明周期 hooks,主要看 injectHook 方法就能够了,这里的 target 默认状况下指向 currentInstance,以后会在将某个回调逻辑缓存在 currentInstance 实例的声明周期回调函数数组中
  • apiOptions.ts:其中包含对于 component 如何解析 options 的实现逻辑,代码比较长同时也比较复杂,耦合性与其余几个文件较高。但其实没有必要直接看完它内部的所有代码,由于 options 中每一段的解析逻辑互相之间都是独立的,所以能够专门针对某个 option 单独去看它内部的解析逻辑,我目前只看了 data 以及 lifecycle
  • apiReactivity.ts:就是对 reactivity 包中的 api 的从新导出,没有什么额外的东西
  • apiWatch.ts: 暂时还没仔细看,不过根据名字可知是和 watch 相关的 api,粗略的看了一下,发现耦合性比较低,所以能够往后再看

组件相关

  • component.ts: 主要包含如何建立一个内部组件实例的逻辑,代码比较长,可是点进去看的话,会发现它实际上是在调用其余模块的暴露的 api,自己的逻辑仍是比较简单的。须要注意的是,这个文件会暴露一对 setCurrentInstance 和 getCurrentInstance 方法用来维护 currentInstance 变量的指向,同时它会在别的模块中被使用到
  • componentProxy.ts: 声明了 render proxy 的实现逻辑,这个 proxy 主要负责外部如何与内部组件实例进行交互,能够将它看作是一个外部组件实例
  • componentProps.ts: 主要看 resolveProps,实现了如何解析各类形式的 props
  • componentSlots.ts:主要看 resolveChildren,实现了如何解析各类形式的 children 节点
  • componentRendererUtils.ts: 一些渲染组件的 util 方法,按名字了解各个方法的含义便可
  • createRenderer.ts:这个和其余文件耦合度较低,能够理解为 VNode 的渲染器,只要实现了其接口,能够在任何上下文环境中进行渲染,好比小程序、nativecanvas 或者内存环境,关于如何编写一个 renderer,直接看 runtime-test 或者 runtime-dom 的代码便可
  • directives.ts: 指令相关的内部 api,当前的代码版本,这部分可能不少 todo 所以能够往后再回来看看

其余

  • errorHandling.ts: 错误处理相关,暂时还没仔细看
  • scheduler.ts: 做业调度器相关,暂时还没仔细看
  • shapeFlags.ts: 组件自己和 children 类型的枚举声明及常量
  • suspense.ts: suspense 相关,暂时还没看,对于其余文件中的 suspense 的相关逻辑,我彻底是按照 react 中相关概念来理解的,暂时没遇到任何障碍
  • warning.ts: 警告相关,大部分是一些 util 方法,按名字理解其含义就行了

推荐的阅读顺序

直接说我本身的阅读顺序,我认为仍是比较符合认知习惯的:

  • 先看 vnode.tsh.ts 等关于 vdom 的代码了解一下新的 VNode 的数据结构
  • 而后再看 apiApp.ts,看挂载过程是怎样把 VNode 和渲染上下文关联起来的,这个过程当中天然会涉及到各类 apixxx.ts 中的内容,挨个看就行了
  • 因为以前看的都是公共 api,须要了解实现细节的话,要进一步看 component.ts,其中主要包含内部组件实例的数据结构以及建立流程,一样地,打断点一行一行读便可
  • 对于一些解析、工具方法,能够放到最后再看其实现细节,打断点的过程当中没有必要一探到底,由于有些方法的名字已经能够很明确的说明其背后实现的逻辑是什么了

期间会遇到 suspenselifecycle 之类的代码,这类代码也能够当作单独的内容进行阅读,在一开始看的时候,也能够不要太纠结于细节,当对总体流程有一个大概了解以后再回头来看会清晰不少,以后我会专门整理一篇文章介绍这块是如何实现的。

写在最后

虽然 vue-next 的代码如今还处在初期的阶段,可是总体的阅读体验仍是不错的,结构清晰,可读性也比较高,一些关键模块也有注释进行说明,惟一不足的地方在于,不少地方仍是借助 as 关键字来进行类型断言,我以为这些地方可能有更好的方式实现类型推断吧。


关注 全栈_101,只谈技术,不谈人生
2893932490-5c7a3ce675beb_articlex.jfif


另:接各类规模全栈外包项目,有意者私聊

相关文章
相关标签/搜索