一文带你从Vue2.x大迈步走进Vue.js 3.0新时代
目錄
- 前言
- 源碼組織方式
- 源碼組織方式的變化
- packages目錄下都是獨立發(fā)行的包,可以獨立使用。
- 不同的構(gòu)建版本
- Composition API的設(shè)計動機(jī)
- Composition API 最佳學(xué)習(xí)參考:
- 設(shè)計動機(jī)
- 總結(jié):
- 性能提升
- Vue 3.0的性能提升主要有以下幾方面:
- 總結(jié)
前言
Vue2.x 與及Vue 3.x都已經(jīng)出來很久了,種種原因,它們的區(qū)別一直沒搞太明白,今天就通過這篇文章給大家梳理一下Vue3.0升級過后帶來了哪些新特性以及這些性變化帶來的各方面性能或者代碼質(zhì)量的提升。
這里占用大家一杯奶茶的時間,反正不花錢,看了沒收獲的評論區(qū)懟我便是😁。
源碼組織方式
源碼組織方式的變化
- 源碼采用TypeScript重寫
大型項目的開發(fā)都推薦使用類型化的語言 - 使用Monorepo管理項目結(jié)構(gòu)
- 使用一個項目來管理多個包
- 把不同的功能代碼放到不同的packages中管理,功能劃分模塊更明確,模塊間的依賴關(guān)系也很明確
- 每個功能模塊都可以單獨進(jìn)行開發(fā)、單獨測試和單獨使用
- packages目錄結(jié)構(gòu)如下:
packages目錄下都是獨立發(fā)行的包,可以獨立使用。
-
compiler-* 編譯相關(guān)的代碼
- compiler-core: 平臺無關(guān)的編譯器
- compiler-dom: 瀏覽器平臺下的編譯器,依賴于compiler-core
- compiler-sfc: 單文件組件的編譯器,依賴于compiler-core和compiler-dom
- compiler-ssr:服務(wù)端渲染的編譯器,它依賴與compiler-core和compiler-dom
-
reactivity:數(shù)據(jù)響應(yīng)式系統(tǒng),可以獨立使用。
-
runtime-* 運行時相關(guān)的代碼
- runtime-core:與平臺無關(guān)的運行時
- runtime-dom:針對瀏覽器的運行時,它處理原生DOM的API、屬性、事件等。
- runtime-test:專門為測試而編寫去的輕量級運行時,這個運行時渲染出來的DOM樹是一個js對象,所以這個運行時可以運行在所有的js環(huán)境里。可以使用它來測試渲染是否正確。它還可以用于序列化DOM,觸發(fā)DOM事件,以及記錄某次更新中的DOM操作。
-
server-render:用于服務(wù)端渲染;
-
shared:vue內(nèi)部使用的一些公共的API
-
size-check:一個私有的包,不會發(fā)布到npm。它的左右時在構(gòu)建時tree-shaking之后檢查包的大小。
-
template-explorer:在瀏覽器中運行的實時編譯組件,它會輸出render函數(shù),該包里面提供了在線訪問的地址,我們后面會用到的。
-
vue:它是用來構(gòu)建完整版的vue,依賴與compiler和runtime。
不同的構(gòu)建版本
與Vue2.x類似,Vue3.0在構(gòu)建大的時候都構(gòu)建了不同的版本,可以在不同的場合下使用。
與Vue2.x不同的是,Vue3.0中不再構(gòu)建umd模塊化的方式。因為umd模塊化的方式會讓代碼有更多的冗余,它要支持多種模塊化的方式。
Vue3.0的構(gòu)建版本中,把 cjs、ES Module 和 自執(zhí)行函數(shù)(IIFE)的方式分別打包到了不同的文件中。在packages/vue目錄的dist中存放了vue 3的所有構(gòu)建版本。
可分為四大類:
- cjs: 也就是commonjs 的模塊化方式,都是完整版的,包含運行時和編譯器。vue.cjs.js和生產(chǎn)版本的vue.cjs.prod.js
- global:也就是全局的意思,它們都可以在瀏覽器中直接通過script標(biāo)簽來導(dǎo)入,導(dǎo)入js之后會增加一個全局的Vue對象。
- vue.global.js 和 vue.global.prod.js 都是完整版的vue,包含運行時和編譯器。
- vue.runtime.global.js和vue.runtime.global.prod.js 它兩是只包含運行時的構(gòu)建版本。
- browser:文件名都包含esm,也就是 ES Module,瀏覽器原生模塊化的方式。在瀏覽器中可以直接通過 <script type="module" src="xxx.esm-xxx.js">的方式來導(dǎo)入這些模塊。
- vue.esm-browser.js 和 vue.esm-browser.prod.js 都是ESModule模塊化方式的完整版的vue,包含運行時和編譯器。
- vue.runtime.esm-browser.js和vue.runtime.esm-browser.prod.js 它兩是ESModule模塊化方式的只包含運行時的構(gòu)建版本。
- bundler:文件沒有打包所有的代碼,它們需要配合打包工具來使用,都是使用ESModule模塊化的方式,內(nèi)部通過import導(dǎo)入runtime-core。
- vue.esm-bundler.js :是完整版的,包含運行時和編譯器的ESModule版本。所有它內(nèi)部還導(dǎo)入了runtime-compiler。
- vue.runtime.esm-bundler.js:是只包含運行時的構(gòu)建版本,我們使用vue cli腳手架工具創(chuàng)建的項目中,默認(rèn)導(dǎo)入使用的就是vue.runtime.esm-bundler.js,也就是它是vue的一個最小版本。在項目開發(fā)完畢后,重新打包的時候,只會打包我們使用到的代碼。它可以讓vue的體積更小。
Composition API的設(shè)計動機(jī)
Composition API 最佳學(xué)習(xí)參考:
- RFC(Request For Comments)vue2.x 升級到vue3的大的變動,都是通過rfc機(jī)制的機(jī)制進(jìn)行確認(rèn)。也就是官方會給出一些提案,結(jié)合社區(qū)收集到的反饋并討論,最終確認(rèn)。 具體參考vuejs的RFC倉庫
- Composition API RFC 該文檔中介紹了 Composition API的使用。
設(shè)計動機(jī)
vue 2.x在開發(fā)中小型項目的時候已經(jīng)很好用,但是使用vue2.x在開發(fā)需要長期迭代和維護(hù)的大型項目的時候,也會有一些限制。在大型項目中, 可能會有一些功能比較復(fù)雜的組件,我們在看他人開發(fā)的組件的時候,可能會很難看懂,原因是vue2.x版本的組件開發(fā)采用的是Options API。
-
Options API
- 用包含一個描述組件選項(data、props、methods、provide、injects、mixins、watched、computed、lifehooksxxx等)的對象來創(chuàng)建組件的方式;
- Options API 開發(fā)復(fù)雜組件,同一個功能邏輯的代碼被拆分到不同選項,我們在看他人寫的代碼的時候為了查看某個功能,可能會需要不停的上下拖動滾動條來找到同一功能對應(yīng)的代碼。
- 案例:
基本每個選項都相互有所依賴,我們需要上下來回翻看以更好地理解代碼。加入我們想要增加搜索功能,那么我們也要像這樣在data中添加相應(yīng)的數(shù)據(jù),在鉤子函數(shù)和方法methods中添加處理邏輯的方法。
另外,使用Options API 還難以提取組件中可重用的邏輯。雖然Vue2.x中有mixins混入的機(jī)制,可以把組件當(dāng)中重復(fù)的代碼提取并重用。但是mixins使用的過程也有問題,比如命名沖突或數(shù)據(jù)來源不清晰。
-
Composition API:
- 它是Vue3.0 中新增的一組API
- 一組基于函數(shù)的API
- 可以更靈活的組織組件的邏輯
案例演示:
案例中還是實現(xiàn)上面vue2 options api案例的功能,在Vue3.0中這里將它們數(shù)據(jù)和處理邏輯封裝到了一個函數(shù)中,useMousePosition(){...}其他組件也可以直接使用這個函數(shù)所封裝的功能,只需要把該方法useMousePosition(){...}提取到一個模塊中,然后再在其他組件中導(dǎo)入即可。
當(dāng)我們需要新增功能的時候,例如要添加搜索功能的時候,我們只需要添加一個useSearch(){...}的函數(shù),將來哪個組件需要,只需要在哪個需要的組件的setup函數(shù)中來調(diào)用這些use*函數(shù)。
這樣做的好處是: - 查看某個邏輯的時候,只需要關(guān)注具體的函數(shù)即可;當(dāng)前的邏輯代碼都封裝在函數(shù)內(nèi)部。
- 官方給出的效果比對如圖所示:
從圖中我們可以看出,相同顏色塊標(biāo)示的代碼屬于同一功能的相關(guān)代碼,使用Composition API的相同顏色的代碼相對更加集中。更有利于對代碼的提取和重用。
值得注意的是,Vue 3.0中既可以使用Options API 也可以使用 Composition API。
Composition API 對于Vue 3.0來說只是一種新增的API,并沒有把Vue2.x的 Options API 的代碼編寫方式拋棄。 你可以根據(jù)自己的喜好以及團(tuán)隊的約定來選擇使用哪種方式。
如果你開發(fā)的組件中有需要提取可復(fù)用的邏輯,這個時候可以考慮選用Composition API,會更方便一些。
總結(jié):
- Composition API是vue 3.0新增的,
- 它提供了一種基于函數(shù)的API,
- 讓我們可以更靈活地組織組件的邏輯,使用Composition API可以更合理組織組件內(nèi)部的代碼結(jié)構(gòu),還可以把一些邏輯功能從組件中提取出來,方便其他組件重用。
其實,這里可以思考個問題,options API是不是本來也可以這樣拆分,再在整體export default 的時候進(jìn)行object merge?
那么可否認(rèn)為這個Composition API就是在做的這件事,把代碼按邏輯劃分函數(shù)化輸出結(jié)果,最后在setup的時候進(jìn)行合并。
性能提升
Vue 3.0的性能提升主要有以下幾方面:
-
響應(yīng)式系統(tǒng)升級
- vue 2.x中響應(yīng)式系統(tǒng)的核心是defineProperty(),初始化的時候給會遍歷data選項中的所有成員,給每個成員屬性及迭代其子對象的每個屬性成員設(shè)置getter/setter來監(jiān)聽數(shù)據(jù)的變化,通過觀察者以及依賴更新的模式使得數(shù)據(jù)響應(yīng)式成為可能,使之成員響應(yīng)式對象。這里面的data成員即使你沒有使用,也會在初始化的時候進(jìn)行響應(yīng)式處理。
- vue3.0使用Proxy對象重寫了響應(yīng)式系統(tǒng)。
- Proxy對象的性能本身就比defineProperty要好;
- Proxy可以監(jiān)聽動態(tài)新增的屬性,而Vue2.x中需要調(diào)用Vue.set()來處理。
- Proxy可以監(jiān)聽刪除的屬性,而Vue2.x中監(jiān)聽不到屬性的刪除。
- Proxy可以監(jiān)聽數(shù)組的索引和length屬性,而Vue2.x中監(jiān)聽不到數(shù)組的索引和length屬性的變更。
- Proxy可以監(jiān)聽數(shù)據(jù)的一切變更,不需要初始化的時候遍歷所有的屬性;
- 此外,如果有多層屬性嵌套的話,只有訪問某個屬性的時候才會遞歸處理下一級的屬性。
-
編譯優(yōu)化
通過優(yōu)化編譯的過程,和重寫虛擬DOM提升了渲染的性能。讓首次渲染和組件更新的的渲染有了大幅度的提升。-
vue2.x中通過標(biāo)記靜態(tài)根節(jié)點,優(yōu)化了diff的過程。而其靜態(tài)節(jié)點還需要進(jìn)行diff,這個過程沒有被優(yōu)化。
-
Vue3.0中標(biāo)記和提升所有的靜態(tài)根節(jié)點,diff的時候只需要對比動態(tài)節(jié)點內(nèi)容
- 新引入 Fragments(片段特性) (在VSCODE中需要升級vetur插件以解決沒有唯一根節(jié)點的錯誤提示),模版中不需要再創(chuàng)建唯一的根節(jié)點,模版中可以直接放文本內(nèi)容,或者多個同級的標(biāo)簽,沒有唯一根節(jié)點時會幫忙自動創(chuàng)建fragment作為根節(jié)點,保持組件內(nèi)部的樹形結(jié)構(gòu),可以找到唯一的根。
- 靜態(tài)提升:編譯時如果開啟了靜態(tài)提升,會把靜態(tài)根節(jié)點(標(biāo)簽內(nèi)的內(nèi)容是純文本的內(nèi)容)提升到生成的render函數(shù)的外部作為const常量定義,這些被提升到的靜態(tài)節(jié)點只有在初始化的時候被創(chuàng)建一次。當(dāng)我們再次調(diào)用render函數(shù)的時候不需要再創(chuàng)建這些靜態(tài)節(jié)點。因為它們已經(jīng)被創(chuàng)建過,可以直接重用初始化時創(chuàng)建的這些靜態(tài)節(jié)點對應(yīng)的Vnode。
-
patch flag: 將來在diff的時候會跳過靜態(tài)根節(jié)點,只需要去更新patch flag所指示的動態(tài)節(jié)點中的內(nèi)容。這大大提升了diff的性能。
- 緩存事件處理函數(shù):減少了不必要的更新操作。
- 緩存事件處理函數(shù):減少了不必要的更新操作。
總結(jié)
-
-
源碼體積優(yōu)化
通過優(yōu)化源碼的體積,和更好的tree-shaking的支持,減少了打包的體積。- Vue.js 3.0中移除了一些不常用到的API,例如 inline-template、filter等。可以讓最終代碼的體積變小。移除的filter可以通過methods或者computed來實現(xiàn)。
- 對tree-shaking的支持更好,Tree-shaking依賴ES Module的模塊化語法的靜態(tài)結(jié)構(gòu)(export / import),通過編譯階段的靜態(tài)分析,找到?jīng)]有引入的模塊,在打包到的時候直接過濾掉,讓打包后的代碼體積更小。Vue 3在設(shè)計之初就考慮到了Tree-shaking的需要,其內(nèi)置的組件,例如:transaction、keep-alive以及一些內(nèi)置的指令,如:v-model等都是按需引入的。除此以外,Vue 3 中的很多API 都是支持Tree-shaking的。所以Vue 3中一些新增的API 如果你沒有使用的話,這部分的代碼是不會打包的,只會打包我們所使用的API。
- 但是默認(rèn)vue的核心模塊都會被打包。
總結(jié)
以上是生活随笔為你收集整理的一文带你从Vue2.x大迈步走进Vue.js 3.0新时代的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 人体十大最佳黄金时间
- 下一篇: html5倒计时秒杀怎么做,vue 设