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 相关文章推荐
使用js在页面中绘制表格核心代码
Sep 16 Javascript
Javascript排序算法之计数排序的实例
Apr 05 Javascript
jQuery/CSS3图片特效插件整理推荐
Dec 07 Javascript
jQuery实现获取table表格第一列值的方法
Mar 01 Javascript
JS封装的自动创建表格的实现代码
Jun 15 Javascript
JS中递归函数
Jun 17 Javascript
深入学习Bootstrap表单
Dec 13 Javascript
javascript设计模式之中介者模式学习笔记
Feb 15 Javascript
利用Vue实现移动端图片轮播组件的方法实例
Aug 23 Javascript
node.js 用socket实现聊天的示例代码
Oct 17 Javascript
基于Vue开发数字输入框组件
Dec 19 Javascript
Vue 父子组件的数据传递、修改和更新方法
Mar 01 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
德生BCL3000的电路分析和打磨
2021/03/02 无线电
php中sprintf与printf函数用法区别解析
2014/02/17 PHP
php操作MongoDB类实例
2015/06/17 PHP
php技术实现加载字体并保存成图片
2015/07/27 PHP
Mootools 1.2教程 滑动效果(Slide)
2009/09/15 Javascript
Jquery css函数用法(判断标签是否拥有某属性)
2011/05/28 Javascript
基于jquery的无刷新分页技术
2011/06/11 Javascript
JS 控件事件小结
2012/10/31 Javascript
js/html光标定位的实现代码
2013/09/23 Javascript
BootStrap glyphicons 字体图标实现方法
2016/05/01 Javascript
jQuery轻松实现表格的隔行变色和点击行变色的实例代码
2016/05/09 Javascript
Jquery修改image的src属性,图片不加载问题的解决方法
2016/05/17 Javascript
JS修改地址栏参数实例代码
2016/06/14 Javascript
jQuery实现的简单拖拽功能示例
2016/09/13 Javascript
js实现百度地图定位于地址逆解析,显示自己当前的地理位置
2016/12/08 Javascript
微信小程序 122100版本更新问题解决方案
2016/12/22 Javascript
微信小程序 网络请求(post请求,get请求)
2017/01/17 Javascript
利用JS实现文字的聚合动画效果
2017/01/22 Javascript
vue的toast弹窗组件实例详解
2018/05/14 Javascript
在 Angular6 中使用 HTTP 请求服务端数据的步骤详解
2018/08/06 Javascript
解决axios发送post请求返回400状态码的问题
2018/08/11 Javascript
简述vue状态管理模式之vuex
2018/08/29 Javascript
详解在React-Native中持久化redux数据
2019/05/22 Javascript
Postman如何实现参数化执行及断言处理
2020/07/28 Javascript
jquery实现简单自动轮播图效果
2020/07/29 jQuery
arcgis.js控制地图地体的显示范围超出区域自动弹回(实现思路)
2021/01/28 Javascript
javascript实现倒计时提示框
2021/03/02 Javascript
python在windows命令行下输出彩色文字的方法
2015/03/19 Python
Python实现基于权重的随机数2种方法
2015/04/28 Python
浅谈python字典多键值及重复键值的使用
2016/11/04 Python
在Python运行时动态查看进程内部信息的方法
2019/02/22 Python
python学习——内置函数、数据结构、标准库的技巧(推荐)
2019/04/18 Python
基于HTML5 audio元素播放声音jQuery小插件
2011/05/11 HTML / CSS
美国在线自行车商店:Jenson USA
2018/05/22 全球购物
大学生志愿者感言
2014/01/15 职场文书
高中打架检讨书
2014/02/13 职场文书