Vue3源碼解讀--方向篇
一、前言
vue3文檔地址、GitHub項(xiàng)目地址:
https://cn.vuejs.org/v2/api/
https://github1s.com/vuejs/vue-next/tree/3.2
最近有小伙伴私聊廣東靚仔,想系統(tǒng)的看vue3的源碼,vue作為他主要的技術(shù)棧,想深入學(xué)習(xí)vue3,但是vue3太大了,無從下手。
廣東靚仔接下來會寫幾期直白的Vue3源碼的文章~
二、如何本地調(diào)試vue3源碼
很多時(shí)候我們都是在本地調(diào)試vue3的源碼,然后沿著調(diào)用鏈,一步一步的去梳理vue3的源碼。
把vue3項(xiàng)目拉到我們本地后,找到rollup.config.js文件,如下圖所示:
然后在第85行開啟sourcemap配置開啟,
Source map是啥
簡單理解:
Source map就是一個(gè)信息文件,里面儲存著位置信息。轉(zhuǎn)換后的代碼的每一個(gè)位置,所對應(yīng)的轉(zhuǎn)換前的位置。
有了Source map,出錯(cuò)的時(shí)候,除錯(cuò)工具將直接顯示原始代碼,而不是轉(zhuǎn)換后的代碼,這樣調(diào)試起來就會非常方便。
然后在你想調(diào)試的地方增加debugger即可
三、vue3有哪些不同
靜態(tài)類型檢查
我們都知道vue2是使用了Flow。
Flow是啥?
Flow 是 Facebook 推出的,作為JavaScript 靜態(tài)類型檢查工具,它以非常小的成本對已有的 JavaScript 代碼遷入,非常靈活。But對于一些復(fù)雜場景類型的檢查,支持得并不好。
在vue2中,我們有時(shí)候看到過一些any有人就吐槽了。
Vue3 沒用 Flow ,而是采用 TypeScript 重構(gòu)了整個(gè)項(xiàng)目。
Why?
TypeScript提供了更好的類型檢查,它能支持復(fù)雜的類型推導(dǎo);
源碼使用 TypeScript 編寫,不再需要去單獨(dú)維護(hù) d.ts 文件,而且就整個(gè) TypeScript 的生態(tài)來看,TypeScript 團(tuán)隊(duì)也是越做越好,TypeScript 本身保持著一定頻率的迭代和更新,支持的 feature 也越來越多。
代碼管理
Vue2 源碼都是在src 目錄下,如下圖所示:
紅色框住的:compiler、core、platforms、server、sfc、shared目錄:
compiler:模板編譯的相關(guān)代碼
core:與平臺無關(guān)的通用運(yùn)行時(shí)代碼
platforms:平臺專有代碼
server:服務(wù)端渲染的相關(guān)代碼
sfc:.vue 單文件解析相關(guān)代碼
shared: 共享工具代碼
monorepo
Vue3 是通過 monorepo 的方式來維護(hù),目錄如下圖所示:
我們可以看到packages文件中放了功能不同的模塊。下面我們拿其中compiler-core展開來看,如下圖所示:
每個(gè) package都有各自的 API、類型定義和測試。
Why?
廣東靚仔認(rèn)為是這樣的:把每個(gè)模塊拆分更細(xì),那么它們之間的職責(zé)劃分更明確,模塊之間的依賴也更加清楚,方便我們閱讀、理解和調(diào)試代碼,很明顯這樣做是可以提高代碼的可維護(hù)性。
還有更重要的一點(diǎn),如果我們只是想使用這些包中的某一個(gè),我們可以單獨(dú)安裝,而不需要安裝整個(gè)vue。
Composition API
Vue3.0 提供了 Composition API,可以看到在語法進(jìn)行了優(yōu)化。
優(yōu)化邏輯組織
將某個(gè)邏輯相關(guān)的代碼全都放在一個(gè)函數(shù)里,這樣就一目了然,看代碼的時(shí)候我們就不需要切換目錄。
邏輯復(fù)用
vue2使用mixins達(dá)到代碼復(fù)用,用的人爽,后面維護(hù)的人,心里估計(jì)已經(jīng)在拔刀了。
vue3我們可以用hook 函數(shù),然后引入調(diào)用即可。
性能優(yōu)化
vue3打包優(yōu)化
使用 tree-shaking 的技術(shù),減少打包體積。Tree-shaking的本質(zhì)是消除無用的js代碼,也就是說我們在開發(fā)的時(shí)候不引入這個(gè)模塊的所有代碼,只引入需要的代碼,打包后,只會包含我們引入的。
tree-shaking 依賴 ES2015 模塊語法的靜態(tài)結(jié)構(gòu)(即 import 和 export),通過編譯階段的靜態(tài)分析,找到?jīng)]有引入的模塊并打上標(biāo)記。
Tips:如果項(xiàng)目使用了 Transition、KeepAlive 等組件,也會被打包的~
優(yōu)化編譯過程
掛載過程,如下圖:
編譯過程,如下圖:
我們知道在數(shù)據(jù)劫持以及patch可以優(yōu)化的地方比較多,vue3在編譯階段對靜態(tài)模板的分析,編譯生成了 Block tree。基于動(dòng)態(tài)節(jié)點(diǎn)指令切割,每個(gè)區(qū)塊內(nèi)部的節(jié)點(diǎn)結(jié)構(gòu)是固定的,以一個(gè) Array 來追蹤自身包含的動(dòng)態(tài)節(jié)點(diǎn)。Vue 將 vnode 更新性能與動(dòng)態(tài)內(nèi)容的數(shù)量相關(guān),很大程度提升性能。
Vue 3.在編譯階段還對 Slot 的編譯進(jìn)行了優(yōu)化、事件偵聽函數(shù)做了緩存優(yōu)化,運(yùn)行時(shí)重寫了 diff 算法...等等
new Proxy
vue2數(shù)據(jù)劫持需要提前定義好key,vue3中使用Proxy,通過劫持整個(gè)對象 ,Object.defineProperty做不到的,它都可以實(shí)現(xiàn)了。vue3在getter 中遞歸找到真正的內(nèi)部對象然后做響應(yīng)式。這也是性能提升的一個(gè)環(huán)節(jié)。
四、分模塊梳理源碼
vue3挺大的一個(gè)項(xiàng)目,我們可以分模塊來梳理:
provide inject
自定義事件
VNode
動(dòng)態(tài)組件
雙向綁定原理new Proxy
reactive源碼
......等等
五、總結(jié)
在我們閱讀完官方文檔后,我們一定會進(jìn)行更深層次的學(xué)習(xí),比如看下框架底層是如何運(yùn)行的,以及源碼的閱讀。
這里廣東靚仔給下一些小建議:
在看源碼前,我們先去官方文檔復(fù)習(xí)下框架設(shè)計(jì)理念、源碼分層設(shè)計(jì)
閱讀下框架官方開發(fā)人員寫的相關(guān)文章
借助框架的調(diào)用棧來進(jìn)行源碼的閱讀,通過這個(gè)執(zhí)行流程,我們就完整的對源碼進(jìn)行了一個(gè)初步的了解
接下來再對源碼執(zhí)行過程中涉及的所有函數(shù)邏輯梳理一遍
作者:廣東靚仔
歡迎關(guān)注:前端早茶