前言

在最近的Vue Fes大会上,Vue Vapor的作者智子大佬宣布,如果能够得到资金支持,那么Vue Vapor年底就能发布alpha版本了。

关注公众号:【前端欧阳】,给自己一个进阶vue的机会

智子也需要赚钱养活自己

根据尤大透露,过去一年以来智子接受赞助全职在为Vue Vapor工作。现在智子虽然还有赞助,但不再是全职的了。
t3

也就是说现在智子大佬也需要想办法赚钱
养活自己
了,所以上周智子发了一个寻找赞助商的帖子。
t1

智子的目标也很简单,
能够养活他就行了
。并且表示为赞助商服务,开始虽然是封闭开发,最终还是会开源的。
t2

如果不寻求赞助,为了能够养活自己智子就只能去找一份工作了。如果这样Vapor的开发进度可能就会延缓,所以目前来说赞助计划是目前最好的方式了。
t5

目前智子收到的赞助总额不到1000美元(包括尤大的)。

强如智子大佬,做开源也很难养活自己。欧阳也只能略尽绵薄之力(因为我最近也被通知12月底走人了,我们团队将会只剩下leader了)
sponsor

现在的Vue Vapor

现在的Vue Vapor主要有三个特点:没有虚拟DOM、高性能、更小的包体积。

没有虚拟DOM
:意思很简单,就是在Vue Vapor中已经将虚拟DOM给干掉了。

高性能
:因为干掉了虚拟DOM,瓶颈得以突破,所以性能相对提高了很多。
performance

更小的包体积
:包体积大小减少了53.3%。

并且Vue Vapor是目前大家所使用的Vue版本的子集
subset

相比目前的Vue功能要少点,支持Composition API以及
<script setup>

因为Vapor是目前Vue版本的子集,所以无虚拟DOM的Vapor模式和有虚拟DOM的vDom模式之间是互相兼容的。
fusion

在Vapor组件中支持使用vDom模式的组件。同样在vDom组件中也支持使用Vapor模式的组件。并且还支持只使用Vapor模式的情况。

并且Vue生态中的
VueUse

Vue Router

Pinia

Nuxt

组件库
等都会支持Vapor。
compatibility

同样也支持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代码,如下图:
playground

从上图中可以看到Vapor模式下经过编译后会自动生成一个effect回调函数,并且在回调函数中会去直接操作DOM。

至于编译时是如何生成effect回调函数,需要等Vapor稳定后欧阳会继续写文章讲解。

总结

无虚拟DOM
的Vapor模式是
有虚拟DOM
的vDom模式的子集,并且他们之间支持component组件混用。抛弃了虚拟DOM,Vapor轻装上阵后,性能以及包体积相比传统的vDom模式有了很大的提升。
最后就是智子现在在寻求赞助商,让他能够全职开发Vue Vapor的同时能够养活自己。

关注公众号:【前端欧阳】,给自己一个进阶vue的机会

另外欧阳写了一本开源电子书
vue3编译原理揭秘
,看完这本书可以让你对vue编译的认知有质的提升。这本书初、中级前端能看懂,完全免费,只求一个star。

标签: none

添加新评论