vue-next/runtime-core 源码阅读指南详解


Posted in Javascript onOctober 25, 2019

写在前面

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

另一方面,也算是给自己挖一个坑,因为这篇文章中涉及到的很多内容,三言两语肯定是说不清的,这就意味着之后必须要写其他文章来填补这些空白。我会尽可能的将高内聚的模块整理到一起,然后再分享出来,尽量避免陷入罗列代码的境地,从而提高文章质量吧。

阅读笔记我托管在语雀上,不嫌乱的也可以看这里。

准备工作

工欲善其事,必先利其器,要看源码,拿写字板来看肯定是不行的(当然也不排除牛人)。你所需要的就是一个支持代码跳转的编辑器即可,我用的是 VSCode,当然了,如果你用 VIM、Sublime 也是可以的。

另外还需一些储备知识:

  • 由于是阅读 vue-next 的代码,并且是 pre-alpha 的版本,这就要求你对之前 vue 有一定的了解,如果是第一次接触,我觉的阅读源码的意义也不是很大
  • 需要熟练掌握 debug 的基础技巧和流程,通过 debug 的方式来看代码有两个好处
    • debug 过程有清晰地调用栈记录
    • 各种作用域下的变量一目了然
  • 需要对 typescript 有一定掌握程度,最起码给知道 interface、enum 等概念

如何阅读

一般有三种途径:

  • 直接看
  • 通过单元测试的可执行代码
  • 自己编写的可执行代码

这里推荐第二种方式,因为单元测试是官方团队维护的,质量肯定有保证,二来单元测试一般都很简单,同时带有注释,这有利于我们理解代码。

由于 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 个比较重要的接口需要看一下,App、AppConfig 和 AppContext,如果对于 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 的渲染器,只要实现了其接口,可以在任何上下文环境中进行渲染,比如小程序、native、canvas 或者内存环境,关于如何编写一个 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.ts 和 h.ts 等关于 vdom 的代码了解一下新的 VNode 的数据结构
  • 然后再看 apiApp.ts,看挂载过程是怎样把 VNode 和渲染上下文关联起来的,这个过程中自然会涉及到各种 apixxx.ts 中的内容,挨个看就好了
  • 由于之前看的都是公共 api,需要了解实现细节的话,要进一步看 component.ts,其中主要包含内部组件实例的数据结构以及创建流程,同样地,打断点一行一行读即可
  • 对于一些解析、工具方法,可以放到最后再看其实现细节,打断点的过程中没有必要一探到底,因为有些方法的名字已经可以很明确的说明其背后实现的逻辑是什么了

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

写在最后

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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
javascript RadioButtonList获取选中值
Apr 09 Javascript
JavaScript 新手24条实用建议[TUTS+]
Jun 21 Javascript
测试JavaScript字符串处理性能的代码
Dec 07 Javascript
JavaScript类和继承 constructor属性
Mar 04 Javascript
灵活应用js调试技巧解决样式问题的步骤分享
Mar 15 Javascript
查看图片(前进后退)功能实现js代码
Apr 24 Javascript
JavaScript的null和undefined区别示例介绍
Sep 15 Javascript
关于在vue 中使用百度ueEditor编辑器的方法实例代码
Sep 14 Javascript
TypeScript开发Node.js程序的方法
Apr 30 Javascript
vue实现条件叠加搜索的解决方法
May 28 Javascript
js数据类型转换与流程控制操作实例分析
Dec 18 Javascript
vue 函数调用加括号与不加括号的区别
Oct 29 Javascript
JS实现简单tab选项卡切换
Oct 25 #Javascript
vue项目从node8.x升级到12.x后的问题解决
Oct 25 #Javascript
JS实现骰子3D旋转效果
Oct 24 #Javascript
Vue可自定义tab组件用法实例
Oct 24 #Javascript
js实现转动骰子模型
Oct 24 #Javascript
js实现固定区域内的不重叠随机圆
Oct 24 #Javascript
js实现随机div颜色位置 类似满天星效果
Oct 24 #Javascript
You might like
PHP中对于浮点型的数据需要用不同的方法解决
2014/03/11 PHP
PHP批量生成图片缩略图的方法
2015/06/18 PHP
laravel框架 laravel-admin上传图片到oss的方法
2019/10/13 PHP
比较详细的关于javascript中void(0)的具体含义解释
2007/08/02 Javascript
jQuery源码分析-03构造jQuery对象-源码结构和核心函数
2011/11/14 Javascript
手机平板等移动端适配跳转URL的js代码
2014/01/25 Javascript
在Firefox下js select标签点击无法弹出
2014/03/06 Javascript
javascript的tab切换原理与效果实现方法
2015/01/10 Javascript
深入理解JavaScript系列(27):设计模式之建造者模式详解
2015/03/03 Javascript
JavaScript在网页中画圆的函数arc使用方法
2015/11/13 Javascript
jQuery fancybox在ie浏览器下无法显示关闭按钮的解决办法
2016/02/19 Javascript
一波JavaScript日期判断脚本分享
2016/03/06 Javascript
jQuery实现导航高亮的方法【附demo源码下载】
2016/11/09 Javascript
jquery.Callbacks的实现详解
2016/11/30 Javascript
Bootstrap源码解读按钮(5)
2016/12/23 Javascript
jQuery轻松实现无缝轮播效果
2017/03/22 jQuery
JS的Ajax与后端交互数据的实例
2018/08/08 Javascript
js常见遍历操作小结
2019/06/06 Javascript
vue2.0+SVG实现音乐播放圆形进度条组件
2019/09/21 Javascript
Node.js API详解之 os模块用法实例分析
2020/05/06 Javascript
带你使用webpack快速构建web项目的方法
2020/11/12 Javascript
centos下更新Python版本的步骤
2013/02/12 Python
简单介绍Python中的len()函数的使用
2015/04/07 Python
python验证码识别的示例代码
2017/09/21 Python
python简易远程控制单线程版
2018/06/20 Python
python面试题Python2.x和Python3.x的区别
2019/05/28 Python
python中for循环把字符串或者字典添加到列表的方法
2019/07/20 Python
Tensorflow设置显存自适应,显存比例的操作
2020/02/03 Python
详解Python yaml模块
2020/09/23 Python
CSS3 box-shadow属性实例详解
2020/06/19 HTML / CSS
Java servlet面试题
2012/03/04 面试题
公务员个人自我评价分享
2013/11/06 职场文书
2014年学生党支部工作总结
2014/12/20 职场文书
幼儿园六一儿童节主持词
2015/06/30 职场文书
Python爬虫基础初探selenium
2021/05/31 Python
MySQL索引是啥?不懂就问
2021/07/21 MySQL