vue-next/runtime-core 源碼閱讀指南詳解
寫在前面
最近又抽時間把 vue-next/runtime-core 的源碼陸陸續(xù)續(xù)地看完了,期間整理了很多筆記,但都是碎片化的。本來是想整理一下,寫成一篇文章分享出來的,但是感覺最終的成果物只能是一篇篇幅巨長的解析文,就算我一行一行的把源碼加上注釋,其閱讀體驗也會很差,因為每個人讀代碼的習慣不同,思路不同。正所謂拋磚引玉,所以,我覺的寫一篇向?qū)淖鳛檫@塊磚應(yīng)該是足夠了,希望可以幫助到想看源碼但覺得無從看起、無從下手的讀者。
另一方面,也算是給自己挖一個坑,因為這篇文章中涉及到的很多內(nèi)容,三言兩語肯定是說不清的,這就意味著之后必須要寫其他文章來填補這些空白。我會盡可能的將高內(nèi)聚的模塊整理到一起,然后再分享出來,盡量避免陷入羅列代碼的境地,從而提高文章質(zhì)量吧。
閱讀筆記我托管在語雀上,不嫌亂的也可以看這里。
準備工作
工欲善其事,必先利其器,要看源碼,拿寫字板來看肯定是不行的(當然也不排除牛人)。你所需要的就是一個支持代碼跳轉(zhuǎn)的編輯器即可,我用的是 VSCode,當然了,如果你用 VIM、Sublime 也是可以的。
另外還需一些儲備知識:
- 由于是閱讀 vue-next 的代碼,并且是 pre-alpha 的版本,這就要求你對之前 vue 有一定的了解,如果是第一次接觸,我覺的閱讀源碼的意義也不是很大
- 需要熟練掌握 debug 的基礎(chǔ)技巧和流程,通過 debug 的方式來看代碼有兩個好處
- debug 過程有清晰地調(diào)用棧記錄
- 各種作用域下的變量一目了然
- 需要對 typescript 有一定掌握程度,最起碼給知道 interface、enum 等概念
如何閱讀
一般有三種途徑:
- 直接看
- 通過單元測試的可執(zhí)行代碼
- 自己編寫的可執(zhí)行代碼
這里推薦第二種方式,因為單元測試是官方團隊維護的,質(zhì)量肯定有保證,二來單元測試一般都很簡單,同時帶有注釋,這有利于我們理解代碼。
由于 vue-next 使用 jest 進行單元測試,在 vscode 中安裝 Jest 插件即可,它支持行內(nèi) debug lens 快捷入口,方便直接對某條單元測試進行 debug。
不過要注意配置一個自定義選項:
"jest.debugCodeLens.showWhenTestStateIn": [
"fail",
"unknown",
"pass", // 注意這里
]
這里的 "pass" 代表即使單元測試通過,也會在上方顯示 debug lens,默認情況下,單元測試用例通過的話,這個 debug lens 標識不會顯示。
模塊職能歸納
runtime-core 目錄下有多個文件,我暫且把每個文件都當做一個子模塊來看待。vue 的代碼質(zhì)量還是挺好的,模塊與模塊之間的耦合性都不是特別高,正因為如此,基本上每個模塊都有自己單獨對應(yīng)的單元測試文件。
我在看的時候,基本上就是挨個看這些模塊的單元測試,然后調(diào)試過程中,會主動的進行一些代碼跳轉(zhuǎn),去看一下具體的實現(xiàn)細節(jié)。下面把當前最新代碼下該文件目錄下的所有模塊的職能進行一些總結(jié)和歸納。
有一些較獨立的模塊我還沒有看完,但是不影響整體的源碼閱讀進程,日后對這些獨立模塊進行單獨研究時,才回來補充這些 todo 就好了。
公共 api 相關(guān)
實現(xiàn)公共 api 的模塊均是以 apixxx 這樣的格式來命名的,如下:
- apiApp.ts: 有 3 個比較重要的接口需要看一下,App、AppConfig 和 AppContext,如果對于 vue2 比較熟悉的話,會很容易理解。createApp 是一個工廠方法,返回一個符合 App 接口約束的對象,其內(nèi)部方法會與一個符合 AppContext 接口約束的對象進行交互。
- apiCreateComponent.ts: 這個文件內(nèi)部包含多個對于 createComponent 函數(shù)簽名的重載聲明,其存在目的應(yīng)該是為了幫助 ts 提供更好的類型推斷以提升開發(fā)體驗。
- apiInject.ts: 組件依賴注入 feature 的實現(xiàn)邏輯,實現(xiàn)方式很簡單,直接與 component 文件中暴露的 currentInstance 變量進行交互,實現(xiàn)繼承、賦值、取值等邏輯
- apiLifecycle.ts: 新的組件聲明周期 hooks,主要看 injectHook 方法就可以了,這里的 target 默認情況下指向 currentInstance,之后會在將某個回調(diào)邏輯緩存在 currentInstance 實例的聲明周期回調(diào)函數(shù)數(shù)組中
- apiOptions.ts:其中包含對于 component 如何解析 options 的實現(xiàn)邏輯,代碼比較長同時也比較復雜,耦合性與其他幾個文件較高。但其實沒有必要直接看完它內(nèi)部的全部代碼,因為 options 中每一段的解析邏輯互相之間都是獨立的,因此可以專門針對某個 option 單獨去看它內(nèi)部的解析邏輯,我目前只看了 data 以及 lifecycle。
- apiReactivity.ts:就是對 reactivity 包中的 api 的重新導出,沒有什么額外的東西
- apiWatch.ts: 暫時還沒仔細看,不過根據(jù)名字可知是和 watch 相關(guān)的 api,粗略的看了一下,發(fā)現(xiàn)耦合性比較低,因此可以日后再看
組件相關(guān)
- component.ts: 主要包含如何創(chuàng)建一個內(nèi)部組件實例的邏輯,代碼比較長,但是點進去看的話,會發(fā)現(xiàn)它其實是在調(diào)用其他模塊的暴露的 api,本身的邏輯還是比較簡單的。需要注意的是,這個文件會暴露一對 setCurrentInstance 和 getCurrentInstance 方法用來維護 currentInstance 變量的指向,同時它會在別的模塊中被使用到
- componentProxy.ts: 聲明了 render proxy 的實現(xiàn)邏輯,這個 proxy 主要負責外部如何與內(nèi)部組件實例進行交互,可以將它看做是一個外部組件實例
- componentProps.ts: 主要看 resolveProps,實現(xiàn)了如何解析各種形式的 props
- componentSlots.ts:主要看 resolveChildren,實現(xiàn)了如何解析各種形式的 children 節(jié)點
- componentRendererUtils.ts: 一些渲染組件的 util 方法,按名字了解各個方法的含義即可
- createRenderer.ts:這個和其他文件耦合度較低,可以理解為 VNode 的渲染器,只要實現(xiàn)了其接口,可以在任何上下文環(huán)境中進行渲染,比如小程序、native、canvas 或者內(nèi)存環(huán)境,關(guān)于如何編寫一個 renderer,直接看 runtime-test 或者 runtime-dom 的代碼即可
- directives.ts: 指令相關(guān)的內(nèi)部 api,當前的代碼版本,這部分可能很多 todo 因此可以日后再回來看看
其他
- errorHandling.ts: 錯誤處理相關(guān),暫時還沒仔細看
- scheduler.ts: 作業(yè)調(diào)度器相關(guān),暫時還沒仔細看
- shapeFlags.ts: 組件本身和 children 類型的枚舉聲明及常量
- suspense.ts: suspense 相關(guān),暫時還沒看,對于其他文件中的 suspense 的相關(guān)邏輯,我完全是按照 react 中相關(guān)概念來理解的,暫時沒遇到任何障礙
- warning.ts: 警告相關(guān),大部分是一些 util 方法,按名字理解其含義就好了
推薦的閱讀順序
直接說我自己的閱讀順序,我認為還是比較符合認知習慣的:
- 先看 vnode.ts 和 h.ts 等關(guān)于 vdom 的代碼了解一下新的 VNode 的數(shù)據(jù)結(jié)構(gòu)
- 然后再看 apiApp.ts,看掛載過程是怎樣把 VNode 和渲染上下文關(guān)聯(lián)起來的,這個過程中自然會涉及到各種 apixxx.ts 中的內(nèi)容,挨個看就好了
- 由于之前看的都是公共 api,需要了解實現(xiàn)細節(jié)的話,要進一步看 component.ts,其中主要包含內(nèi)部組件實例的數(shù)據(jù)結(jié)構(gòu)以及創(chuàng)建流程,同樣地,打斷點一行一行讀即可
- 對于一些解析、工具方法,可以放到最后再看其實現(xiàn)細節(jié),打斷點的過程中沒有必要一探到底,因為有些方法的名字已經(jīng)可以很明確的說明其背后實現(xiàn)的邏輯是什么了
期間會遇到 suspense、lifecycle 之類的代碼,這類代碼也可以當做單獨的內(nèi)容進行閱讀,在一開始看的時候,也可以不要太糾結(jié)于細節(jié),當對整體流程有一個大概了解之后再回頭來看會清晰很多,之后我會專門整理一篇文章介紹這塊是如何實現(xiàn)的。
寫在最后
雖然 vue-next 的代碼現(xiàn)在還處在初期的階段,但是整體的閱讀體驗還是不錯的,結(jié)構(gòu)清晰,可讀性也比較高,一些關(guān)鍵模塊也有注釋進行說明,唯一不足的地方在于,很多地方還是借助 as 關(guān)鍵字來進行類型斷言,我覺得這些地方可能有更好的方式實現(xiàn)類型推斷吧。
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持億速云。