前言
在最近的Vue Fes大會上,Vue Vapor的作者智子大佬宣佈,如果能夠得到資金支援,那麼Vue Vapor年底就能釋出alpha版本了。
關注公眾號:【前端歐陽】,給自己一個進階vue的機會
智子也需要賺錢養活自己
根據尤大透露,過去一年以來智子接受贊助全職在為Vue Vapor工作。現在智子雖然還有贊助,但不再是全職的了。
也就是說現在智子大佬也需要想辦法賺錢養活自己
了,所以上週智子發了一個尋找贊助商的帖子。
智子的目標也很簡單,能夠養活他就行了
。並且表示為贊助商服務,開始雖然是封閉開發,最終還是會開源的。
如果不尋求贊助,為了能夠養活自己智子就只能去找一份工作了。如果這樣Vapor的開發進度可能就會延緩,所以目前來說贊助計劃是目前最好的方式了。
目前智子收到的贊助總額不到1000美元(包括尤大的)。
強如智子大佬,做開源也很難養活自己。歐陽也只能略盡綿薄之力(因為我最近也被通知12月底走人了,我們團隊將會只剩下leader了)
現在的Vue Vapor
現在的Vue Vapor主要有三個特點:沒有虛擬DOM、高效能、更小的包體積。
沒有虛擬DOM
:意思很簡單,就是在Vue Vapor中已經將虛擬DOM給幹掉了。
高效能
:因為幹掉了虛擬DOM,瓶頸得以突破,所以效能相對提高了很多。
更小的包體積
:包體積大小減少了53.3%。
並且Vue Vapor是目前大家所使用的Vue版本的子集
相比目前的Vue功能要少點,支援Composition API以及<script setup>
。
因為Vapor是目前Vue版本的子集,所以無虛擬DOM的Vapor模式和有虛擬DOM的vDom模式之間是互相相容的。
在Vapor元件中支援使用vDom模式的元件。同樣在vDom元件中也支援使用Vapor模式的元件。並且還支援只使用Vapor模式的情況。
並且Vue生態中的VueUse
、Vue Router
、Pinia
、Nuxt
、元件庫
等都會支援Vapor。
同樣也支援jsx,不過需要引入unplugin-vue-jsx-vapor
。
Vapor的機制
先看一個普通的操作DOM的例子:
// Initialize
const container = document.createElement('div')
const label = document.createElement('h1')
const button = document.createElement('button')
button.textContent = 'Increase'
button.addEventListener('click', increase)
let count = 0
const render = () => {
label.textContent = `Count: ${count}`
}
function increase() {
count++
render() // Re-render
}
render() // Initial render
document.body.append(container)
container.append(label, button)
在這個例子中主要有兩個元素:h1
標籤和button
按鈕。
h1
標籤中渲染了count
變數的值。
點選button
按鈕觸發click事件執行increase
函式,在函式中首先會執行count++
,然後再去執行render
函式。
在render
函式中將h1
標籤中的值更新為最新值。
上面這個方案有個弊端,每次在click事件的回撥中除了常規的執行count++
之外,還去手動呼叫了render
函式。
設想一下,如果我們的業務程式碼裡面也這樣寫,那程式碼中將會到處都在呼叫render
函式了,這樣的程式碼光想想都頭疼。
還好Vue的設計中有個優秀的響應式機制,並且還將響應式的功能抽取成一個單獨的包:@vue/reactivity
。
而Vue Vapor就是基於@vue/reactivity
進行開發的,藉此實現當響應式資料改變後會自動更新DOM,無需去手動執行render函式。
使用@vue/reactivity
改造後的程式碼如下:
import { effect, ref } from '@vue/reactivity'
// Initialize
const container = document.createElement('div')
const label = document.createElement('h1')
const button = document.createElement('button')
button.textContent = 'Increase'
button.addEventListener('click', increase)
const count = ref(0)
effect(() => {
label.textContent = `Count: ${count.value}`
})
function increase() {
count.value++
}
document.body.append(container)
container.append(label, button)
改造後的程式碼和原來的程式碼主要有三個不同:
-
之前是直接使用
let count = 0
定義的變數,而改造後使用const count = ref(0)
定義的響應式變數。 -
之前的
increase
函式中除了執行count++
之外,還需要去手動呼叫render()
函式。而在新的程式碼中只會執行count.value++
。 -
移除了render函式,替代他的是
effect
函式。在effect
的回撥函式中同樣是進行DOM操作更新h1
標籤中的值。effect
函式和watchEffect
很相似,當回撥中的響應式變數改變後就會重新執行回撥函式。這裡就是當響應式變數count
改變後會重新執行回撥函式,在回撥函式中進行DOM操作更新h1
標籤中的值。
這也就是Vapor基於@vue/reactivity
實現的響應式原理,在這個過程中完全沒有虛擬DOM的介入。當響應式變數改變後會執行對應的effect
回撥函式,在回撥函式中直接去更新DOM即可。
看到這裡有的小夥伴會有疑問,這個effect
函式以及裡面操作DOM的程式碼需要我們自己手寫嗎?
當然不需要手動去寫!!在編譯時Vapor會自動生成一個effect
回撥函式,以及回撥函式里面更新DOM的程式碼。
這個是上面的例子在Vue Vapor SFC Playground
上面經過編譯後的js程式碼,如下圖:
從上圖中可以看到Vapor模式下經過編譯後會自動生成一個effect回撥函式,並且在回撥函式中會去直接操作DOM。
至於編譯時是如何生成effect回撥函式,需要等Vapor穩定後歐陽會繼續寫文章講解。
總結
無虛擬DOM
的Vapor模式是有虛擬DOM
的vDom模式的子集,並且他們之間支援component元件混用。拋棄了虛擬DOM,Vapor輕裝上陣後,效能以及包體積相比傳統的vDom模式有了很大的提升。最後就是智子現在在尋求贊助商,讓他能夠全職開發Vue Vapor的同時能夠養活自己。
關注公眾號:【前端歐陽】,給自己一個進階vue的機會
另外歐陽寫了一本開源電子書vue3編譯原理揭秘,看完這本書可以讓你對vue編譯的認知有質的提升。這本書初、中級前端能看懂,完全免費,只求一個star。