【Vue3源碼分析】講透源碼開(kāi)篇
為什么要學(xué)源碼
- 技術(shù)是第一生產(chǎn)力
- 學(xué)習(xí) API 的設(shè)計(jì)目的、思路、取舍
- 學(xué)習(xí)優(yōu)秀的代碼風(fēng)格
- 學(xué)習(xí)組織代碼的方式
- 學(xué)習(xí)實(shí)現(xiàn)方法的技巧
- 學(xué)習(xí) ES67 新 API、TS 高級(jí)用法
- 不給自己設(shè)限,不要讓你周圍人的技術(shù)上限成為你的上限
- 面試加分項(xiàng)
- 裝逼利器
學(xué)習(xí)源碼副作用
- 畫(huà)虎不成反類犬(強(qiáng)行上馬 vue3,自己焦頭爛額、項(xiàng)目難以維護(hù)、同事苦不堪言)
- 為了用而用,而不是因地制宜
- 喜歡炫技寫(xiě)一下看似高大上,實(shí)際沒(méi)有可讀性,影響團(tuán)隊(duì)協(xié)作的奇技淫巧
vue3 設(shè)計(jì)動(dòng)機(jī)與目的
更好的邏輯復(fù)用與代碼組織
- vue2 option api 的代碼風(fēng)格將同一邏輯點(diǎn)的代碼分散在各處,會(huì)導(dǎo)致讀者關(guān)注點(diǎn)分離,也不利于代碼的邏輯復(fù)用;而 vue3 composition api 將同一業(yè)務(wù)邏輯的代碼聚合在一起命名為 useXXX 函數(shù),再通過(guò) setup 將不同的邏輯組裝起來(lái)并返回給組件 data,明顯更方便邏輯復(fù)用。
- vue2 mixin 用于邏輯復(fù)用的時(shí)候容易導(dǎo)致命名沖突和數(shù)據(jù)來(lái)源不清晰;而 vue3 provide/inject 配合 composition api 可以很方便的找到數(shù)據(jù)來(lái)源并通過(guò)解構(gòu)重命名,明顯更方便邏輯復(fù)用。
更好的類型推導(dǎo)
- 在 methods 中 this 指向組件實(shí)例而不是 method 本身,不利于類型推導(dǎo)。
- 例如 this.、store,每個(gè)新的插件都會(huì)需要向 Vue 追加類型定義。
更新前后對(duì)比
優(yōu)化
- 打包更小(全局 API tree-shaking)
- 渲染、更新更快,內(nèi)存占用減少
- 使用 proxy 取代 Object.defineProperty
- v-model 代替以前的 v-model 和.sync
- 生命周期變更 例如 destroyed beforeDestroy 改為 unmounted beforeUnmount
- 自定義指令 API 與生命周期保持一致
- Diff 算法的提升(靜態(tài)標(biāo)記、靜態(tài)提升)
新特性
- Template 支持多個(gè)根標(biāo)簽
- composition API 實(shí)現(xiàn)邏輯模塊化和復(fù)用
- Teleport 傳送門(mén)組件 代碼塊掛載到任意位置
- Suspense 懸停組件 異步加載組件使用(實(shí)驗(yàn)屬性)
- 使用 @vue/runtime-core 的 createRenderer 自定義渲染器(跨平臺(tái)利器)
- 使用 ts 編寫(xiě)源碼,更好的類型推導(dǎo)、更好的適配 ts
更多變化
概覽:https://v3.cn.vuejs.org/guide/migration/introduction.html
疑問(wèn)解答
問(wèn)題一:compostion api 根本沒(méi)有解決任何問(wèn)題,只是追逐新玩意的東西尤雨溪:不同意這個(gè)觀點(diǎn)。Vue 最開(kāi)始很小,但是現(xiàn)在被廣泛應(yīng)用到不同級(jí)別復(fù)雜度的業(yè)務(wù)領(lǐng)域,有些可以基于 option API 很輕松處理,但是有些不可以。例如下面的場(chǎng)景:
- 有很多邏輯的大型組件(數(shù)百行)
- 在多個(gè)組件可復(fù)用的邏輯
對(duì)于問(wèn)題 1,你需要把每個(gè)邏輯拆分到不同選項(xiàng),例如,一段邏輯需要一些響應(yīng)數(shù)據(jù),一個(gè)計(jì)算屬性,一些監(jiān)聽(tīng)屬性還有方法。你去了解這段邏輯時(shí),需要不斷上下移動(dòng)閱讀,雖然你知道一些屬性是什么類型,但是你并不知道他具體的作用。當(dāng)一個(gè)組件包含多個(gè)邏輯,情況就更糟糕了。如果用新的 API,可以將數(shù)據(jù)和邏輯組合在一起,最重要的是,你可以干凈的把這些邏輯提取到一個(gè)函數(shù),甚至一個(gè)單獨(dú)的文件中。
問(wèn)題二:使用新 API 導(dǎo)致邏輯分散到不同地方,違背"關(guān)注點(diǎn)分離
"尤雨溪:這個(gè)問(wèn)題和項(xiàng)目文件組織方式問(wèn)題類似。我們很多人都同意按文件類型組織(布局放 HTML,樣式 CSS,邏輯 JS)并不是正確的方式,因?yàn)閺?qiáng)制把相關(guān)代碼分割到三個(gè)文件,只是給人一種“關(guān)注點(diǎn)分離”的錯(cuò)覺(jué)。這里的關(guān)鍵是“關(guān)注點(diǎn)”不是由文件類型定義。相反,我們大多數(shù)選擇以功能或者職責(zé)來(lái)組織文件,這正是人們喜歡 Vue 單文件組件的原因。SFC 就是按功能組織代碼的方法,但諷刺的是當(dāng)首次引入 SFC 時(shí),許多人也是拒絕的,認(rèn)為它違反了關(guān)注點(diǎn)分離。
問(wèn)題三:新的語(yǔ)法讓 Vue 失去簡(jiǎn)單性,導(dǎo)致"意大利面條式代碼"的出現(xiàn),降低項(xiàng)目維護(hù)性。
尤雨溪:正好相反,新的 API 就是為了提高項(xiàng)目長(zhǎng)期維護(hù)性的。如果我們查看任何 javascript 項(xiàng)目,都會(huì)從入口文件開(kāi)始閱讀,該文件的本質(zhì)是你的應(yīng)用啟動(dòng)時(shí)被隱式調(diào)用的"main"函數(shù)。如果只有一個(gè)函數(shù)入口,會(huì)導(dǎo)致意大利面條代碼,那所有的 js 項(xiàng)目都是意大利面條代碼。顯然不是的,因?yàn)殚_(kāi)發(fā)人員通過(guò)代碼模塊化或者較小的函數(shù)來(lái)組織代碼。另外,我同意新的 API 理論上會(huì)降低代碼質(zhì)量的最低門(mén)檻。但是我們可以使用以往防止代碼變成意大利面條的手段緩解這種情況。另一方面,新的 API 可以提升代碼質(zhì)量的最高上限,相比 option api,你可以重構(gòu)為質(zhì)量更高的代碼。而且,基于 Option api 你還得解決類似 mixins 的問(wèn)題。很多人認(rèn)為"Vue 失去簡(jiǎn)單性",實(shí)際上只是失去組件內(nèi)代碼類型檢查能力(就是你不知道一個(gè)變量是 data、method、還是 computed)。但是用新的 API,實(shí)現(xiàn)一個(gè)類型檢測(cè)器也是非常容易實(shí)現(xiàn)以前的特性的。也就是說(shuō),你不應(yīng)該被 option api 限制思維,而更多關(guān)注邏輯內(nèi)聚問(wèn)題。
源碼調(diào)試
安裝源碼及依賴(安裝依賴出錯(cuò)一般是 npm 淘寶源的問(wèn)題或者需要梯子)
- git clone https://github.com/vuejs/vue-next.git
- yarn install
- yarn dev --sourcemap
對(duì)源碼進(jìn)行打包
- yarn dev --sourcemap
新建 packages/vue/examples/index.html 用于測(cè)試
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>Title</title>
- </head>
- <body>
- <div id="app">
- <div>
- <div>test demo {{msg}}</div>
- <div>test demo {{msgMore}}</div>
- </div>
- </div>
- <script src="../dist/vue.global.js"></script>
- <script>
- Vue.createApp({
- setup() {
- const msg = Vue.ref('Hello')
- const msgMore = Vue.computed(()=>msg.value+' world')
- return {
- msg,
- msgMore
- }
- }
- }).mount('#app')
- </script>
- </body>
- </html>
谷歌瀏覽器打開(kāi) index.html F12
本文轉(zhuǎn)載自微信公眾號(hào)「微醫(yī)大前端技術(shù)」































