作为一个Vue的重度用户,我从Vue 2.0时代就一直在用Vue做项目,大大小小的项目做了十几个,也算是积累了一些经验。从2017年开始,就不断有Vue 3.0的消息传出来,说Vue 3.0会重写核心,会有很多激动人心的新特性,性能会有大幅提升。作为一个Vue粉,我一直非常期待Vue 3.0的到来。
2018年初,Vue 3.0的设计思路和新特性慢慢浮出水面,Evan You(尤雨溪)也在各种场合分享了Vue 3.0的进展。我按捺不住好奇心,开始尝试学习和体验Vue 3.0的新特性。但是这个过程并不顺利,从最开始的兴奋期待,到中间的困惑迷茫,再到最后的"从入门到放弃",我经历了很多。
今天就来记录一下我学习Vue 3.0前瞻的真实经历,包括Vue 3.0有哪些新特性、我遇到了哪些坑、为什么说"从入门到放弃",以及对Vue 3.0的一些思考和期待。
一、为什么对Vue 3.0这么期待
先说说我为什么对Vue 3.0这么期待。
我用Vue 2.0做了很多项目,总体来说体验非常好。Vue的学习曲线平缓,文档友好,生态完善,开发效率很高。但是用久了之后,也发现了一些Vue 2.0的痛点和局限。
痛点一:响应式系统的局限
Vue 2.0的响应式系统是基于Object.defineProperty实现的。这个方案有一些固有的局限:
- 不能检测对象属性的添加和删除,需要用Vue.set和Vue.delete来处理。
- 不能检测数组索引的直接修改和长度变化,需要用Vue.set或者数组的变异方法。
- 初始化时需要递归遍历整个对象,把所有属性都转换成getter/setter,对于大型对象,初始化的性能开销比较大。
这些问题在日常开发中经常遇到,虽然有解决方案,但是总是觉得不够优雅。特别是做大型项目的时候,对象嵌套很深,数据量很大,响应式初始化的性能问题就比较明显了。
痛点二:大型组件的逻辑复用困难
在Vue 2.0中,组件逻辑复用主要靠mixins。mixins虽然能实现逻辑复用,但是有很多问题:
- 命名冲突:多个mixins可能有同名的属性或方法,会互相覆盖。
- 来源不清晰:组件用了多个mixins之后,很难搞清楚某个属性或方法来自哪个mixin。
- 配置合并复杂:mixins的合并规则比较复杂,特别是生命周期钩子、data、methods等的合并,容易出问题。
做大型项目的时候,组件越来越复杂,逻辑越来越多,mixins的这些问题就越来越突出。我曾经做过一个项目,一个组件用了五六个mixins,出了bug之后根本搞不清楚是哪个mixin的问题,调试起来非常痛苦。
痛点三:TypeScript支持不够好
虽然Vue 2.0也能用TypeScript,但是支持得不够理想。因为Vue 2.0的API是基于选项式的,类型推导比较困难,在TypeScript中使用Vue经常需要写很多类型声明,开发体验不够好。
我们团队最近在考虑引入TypeScript,但是调研了一下Vue 2.0 + TypeScript的方案,发现要么用vue-class-component加装饰器,要么写很多类型断言,都不是很优雅。所以一直在等Vue 3.0对TypeScript有更好的支持。
痛点四:打包体积偏大
Vue 2.0的核心库打包之后(gzip)大概有30多KB,虽然不算大,但是对于一些对体积敏感的场景(比如移动端、轻量级应用),还是希望能更小一些。而且Vue 2.0中很多功能是全局挂载的,即使你没有用到,也会被打包进去,不能按需加载。
正是因为有这些痛点,我对Vue 3.0充满了期待。听说Vue 3.0会用Proxy重写响应式系统,会引入新的逻辑复用方式,会用TypeScript重写,会有更好的Tree Shaking支持,每一条都正中我的痛点。所以一有Vue 3.0的消息,我就迫不及待地去了解和学习。
二、Vue 3.0有哪些让人兴奋的新特性
2018年初,Evan You在各种分享中透露了Vue 3.0的设计思路和新特性。我整理了一下,主要有以下几个方面,每一个都让人非常兴奋。
新特性一:基于Proxy的响应式系统
这是Vue 3.0最核心的改进。Vue 3.0将用ES6的Proxy来替代Object.defineProperty实现响应式系统。
Proxy的好处是显而易见的:
- 可以检测对象属性的添加和删除,不再需要Vue.set和Vue.delete。
- 可以检测数组的索引修改和长度变化,数组的响应式问题彻底解决。
- 不需要递归遍历整个对象来初始化响应式,只有在属性被访问时才会进行响应式转换,初始化性能大幅提升。
- 支持Map、Set、WeakMap、WeakSet等新的数据结构。
根据Evan You分享的benchmark数据,Vue 3.0的响应式初始化速度比Vue 2.0快了很多,特别是在处理大型对象的时候,性能提升非常明显。而且内存使用也减少了,因为不需要预先把所有属性都转换成getter/setter。
这个改进对我来说是最期待的,因为它解决了Vue 2.0响应式系统的所有痛点,让响应式变得更加自然和高效。
新特性二:基于函数的API(Composition API)
这是Vue 3.0另一个重要的改进,也是争议最大的一个改进。Vue 3.0将引入一种新的基于函数的API(当时叫Function-based API,后来正式命名为Composition API),用来解决组件逻辑复用的问题。
基于函数的API的核心思想是:把组件的逻辑封装成函数,通过函数调用来复用逻辑,而不是用mixins。这种方式的好处是:
- 没有命名冲突:函数内部的变量是局部的,不会和其他函数冲突。
- 来源清晰:通过函数调用,可以清楚地知道某个逻辑来自哪个函数。
- 更好的TypeScript支持:函数式的API天然适合类型推导,TypeScript体验会好很多。
- 更灵活的逻辑组合:可以根据需要自由组合不同的逻辑函数,比mixins灵活得多。
Evan You当时分享了一个例子,用基于函数的API来封装鼠标位置跟踪的逻辑:
function useMouse() {
const x = value(0)
const y = value(0)
const update = e => {
x.value = e.pageX
y.value = e.pageY
}
onMounted(() => {
window.addEventListener('mousemove', update)
})
onUnmounted(() => {
window.removeEventListener('mousemove', update)
})
return { x, y }
}然后在组件中使用:
const Component = {
setup() {
const { x, y } = useMouse()
return { x, y }
},
template: `<div>{{ x }} {{ y }}</div>`
}看到这个例子的时候,我觉得非常惊艳。这种方式比mixins优雅太多了,逻辑清晰,来源明确,没有命名冲突,而且TypeScript支持也好。当时我就觉得,这才是组件逻辑复用的正确打开方式。
新特性三:用TypeScript重写,更好的类型支持
Vue 3.0将用TypeScript重写,从底层就对TypeScript有良好的支持。这意味着:
- Vue的API会有更完善的类型定义,不需要额外的类型声明包。
- 基于函数的API天然适合类型推导,在组件中使用TypeScript会非常顺畅。
- IDE的智能提示和代码补全会更加准确,开发体验大幅提升。
对于我们团队来说,这个改进非常重要。我们一直在考虑引入TypeScript,但是Vue 2.0的TypeScript体验不够好,所以一直在等Vue 3.0。Vue 3.0用TypeScript重写之后,引入TypeScript的阻力就小很多了。
新特性四:更好的性能和更小的体积
Vue 3.0在性能和体积上也有很多改进:
- 响应式系统重写,初始化性能和内存使用都有提升。
- 虚拟DOM重写,通过静态节点提升、基于Proxy的依赖收集等手段,渲染性能提升。
- 更好的Tree Shaking支持,更多功能改为按需导入,打包体积更小。
根据Evan You分享的数据,Vue 3.0的运行时性能比Vue 2.0提升了很多,服务端渲染速度提升了2-3倍,打包体积也减小了不少。对于追求性能和轻量的场景来说,这些改进非常有吸引力。
新特性五:其他改进
除了上面这些,Vue 3.0还有一些其他的改进:
- 支持Fragment(多根节点组件),不再要求组件模板只能有一个根元素。
- 支持Suspense,处理异步组件的加载状态。
- 支持Portals(传送门),可以把组件渲染到DOM树之外的地方。
- 改进的自定义渲染器API,可以更方便地创建自定义渲染器。
- 新的生命周期钩子命名,更加清晰一致。
每一个改进都让人非常期待,当时我觉得Vue 3.0简直就是完美的,迫不及待地想用上。
三、从入门到放弃:我经历了什么
怀着激动的心情,我开始了Vue 3.0的学习之旅。但是这个过程并没有我想象的那么顺利,我经历了从兴奋到困惑再到放弃的全过程。
阶段一:兴奋入门,到处找资料
刚开始的时候,我非常兴奋,到处找Vue 3.0的资料。但是很快我就发现,Vue 3.0的资料太少了。
因为Vue 3.0还在开发中,没有正式发布,所以没有官方文档,没有完整的教程,没有书籍,只有Evan You在各种分享中的PPT和演讲视频,以及GitHub上的一些设计文档和讨论。
这些资料非常零散,而且很多是英文的,需要自己去整理和理解。我花了好几天时间,把能找到的资料都找了一遍,包括:
- Evan You在Vue Conf 2018上的演讲视频和PPT
- GitHub上的vue-next仓库(Vue 3.0的代码仓库)
- RFC(Request for Comments)文档,里面有Vue 3.0各个特性的设计讨论
- 各种技术博客和社区讨论
把这些资料整理完之后,我对Vue 3.0的新特性有了一个大概的了解,但是也只是停留在"知道有什么"的层面,具体怎么用、有什么坑,还是不清楚。
阶段二:尝试写Demo,遇到各种问题
光看资料不行,得动手写代码才能真正理解。于是我决定尝试用Vue 3.0写几个Demo。
但是一开始就遇到了问题:Vue 3.0还没有正式发布,怎么安装?
当时Vue 3.0的代码在vue-next仓库里,还没有发布到npm。要体验Vue 3.0,要么自己从源码构建,要么用一些社区提供的实验性版本。我试了好几种方式,折腾了半天,终于把开发环境搭起来了。
搭好环境之后,我开始写第一个Demo,一个简单的计数器。按照基于函数的API的写法,应该是这样的:
import { value, createApp } from 'vue'
const App = {
setup() {
const count = value(0)
const increment = () => {
count.value++
}
return { count, increment }
},
template: `
<div>
<p>Count: {{ count }}</p>
<button @click="increment">+</button>
</div>
`
}
createApp(App).mount('#app')写的时候就觉得有点别扭,特别是count.value++这个写法。在Vue 2.0中,直接this.count++就可以了,但是在Vue 3.0的基于函数的API中,因为count是一个包装对象(wrapper),需要通过.value来访问和修改实际的值。
这个.value的写法让我很不适应。虽然知道这是为了让基本类型(数字、字符串、布尔值)也能保持响应式,但是写起来确实有点繁琐,而且很容易忘记写.value,导致bug。我写Demo的时候就好几次忘了写.value,调试了半天才发现问题。
写完计数器之后,我又尝试写了一个稍微复杂一点的Demo,包含组件通信、计算属性、生命周期钩子等。这个过程中遇到了更多的问题:
- API一直在变:因为Vue 3.0还在开发中,API很不稳定。今天看的文档是一种写法,明天可能就变了。我刚学会一种写法,过几天发现又改了,之前写的代码都不能用了,需要重新学。这种感觉非常挫败。
- 文档不完善:很多API没有详细的文档,只有一些设计文档和示例,很多细节不清楚。比如错误处理、边界情况、性能注意事项等,都需要自己去摸索,或者去看源码。对于初学者来说,这非常不友好。
- 生态不兼容:Vue 2.0的生态非常完善,有Vuex、Vue Router、Element UI、Vuetify等大量的库和组件库。但是这些库在Vue 3.0中都不能用,需要等它们适配Vue 3.0。当时Vue 3.0还没发布,这些库自然也没有适配版本,所以用Vue 3.0写项目的时候,很多常用的功能都要自己实现,非常不方便。
- 工具链支持不好:Vue 2.0有非常完善的工具链支持,比如Vue DevTools、Vetur、vue-cli等。但是Vue 3.0因为API变了,这些工具都需要更新才能支持。当时这些工具对Vue 3.0的支持都不好,Vue DevTools不能用,Vetur的智能提示不准确,调试非常困难。
写了几个Demo之后,我感觉非常累。每写一个功能都要查半天资料,踩很多坑,而且API还在不断变化,今天写的代码明天可能就不能用了。这种感觉就像是在沙地上盖房子,盖了又塌,塌了又盖,永远看不到成品。
阶段三:困惑迷茫,开始怀疑人生
写了一段时间Demo之后,我开始感到困惑和迷茫。
最大的困惑是:基于函数的API真的比选项式API好吗?
Vue 2.0的选项式API(data、methods、computed、watch等)虽然有逻辑复用的问题,但是它的优点是结构清晰,新手容易上手。一个组件的各个部分分门别类,data是数据,methods是方法,computed是计算属性,一目了然。
而基于函数的API,所有的逻辑都写在setup函数里,虽然逻辑可以封装成函数复用,但是如果组件比较复杂,setup函数可能会变得很长,各种变量和函数混在一起,结构反而不如选项式API清晰。
而且,.value的写法确实很不优雅,也容易出错。虽然Evan You解释说这是为了保持基本类型的响应式,是必要的权衡,但是作为一个使用者,我还是觉得写起来很别扭。
还有一个困惑是:Vue 3.0的学习成本是不是太高了?
Vue一直以"简单易学"著称,这也是它能快速流行的重要原因。但是Vue 3.0引入了很多新的概念和API,基于函数的API、响应式包装对象、新的生命周期钩子等,学习成本比Vue 2.0高了不少。
对于新手来说,Vue 3.0可能不再那么友好了。他们不仅要学习Vue的基本概念,还要理解响应式的原理、函数式API的设计思想、.value的机制等。这会不会让Vue失去"简单易学"的优势?
这些困惑让我开始怀疑,Vue 3.0是不是真的像我想象的那么好。我甚至开始觉得,Vue 2.0其实已经够用了,那些痛点虽然存在,但是也不是不能忍受,有没有必要花这么大的成本去升级到Vue 3.0?
阶段四:从入门到放弃,决定等正式版
在困惑和迷茫中挣扎了一段时间之后,我终于决定:暂时放弃学习Vue 3.0,等正式版发布之后再说。
做出这个决定的原因主要有几个:
- API还不稳定:Vue 3.0还在开发中,API一直在变,现在学了之后可能很快就过时了。与其在不稳定的版本上浪费时间,不如等正式版发布、API稳定之后再学。
- 生态还不成熟:Vue 3.0的生态还没有建立起来,常用的库和工具都没有适配,现在学了也没法在实际项目中用。学了不用,很快就会忘。
- 学习成本太高:在没有完善文档和教程的情况下,学习Vue 3.0的成本太高了,需要自己去摸索,踩很多坑。有这个时间,不如把Vue 2.0用得更熟练,或者学习其他更稳定的技术。
- Vue 2.0还能用:Vue 2.0已经非常成熟和稳定了,生态完善,工具链齐全,完全能满足目前的项目需求。没有必要急着升级到Vue 3.0。
做出这个决定之后,我反而觉得轻松了很多。不再每天追Vue 3.0的消息,不再折腾那些不稳定的API,不再为那些还没确定的设计而困惑。我把精力重新放回到Vue 2.0的项目上,把现有的项目做好,同时关注Vue 3.0的进展,等正式版发布之后再系统地学习。
这就是我的"Vue 3.0前瞻从入门到放弃"的经历。
四、从入门到放弃,我学到了什么
虽然最后"放弃"了,但是这段学习经历并不是完全没有收获的。我从中学到了很多东西。
收获一:对Vue的设计思想有了更深的理解
通过学习Vue 3.0的设计思路和新特性,我对Vue的设计思想有了更深的理解。我明白了Vue 2.0的响应式系统为什么是那样设计的,它有什么局限,Vue 3.0为什么要用Proxy重写。我也明白了组件逻辑复用的难点在哪里,基于函数的API是怎么解决这些问题的。
这些理解不仅有助于我更好地使用Vue 2.0,也让我对前端框架的设计有了更深入的认识。一个好的框架,不仅要功能强大,还要API设计优雅,学习曲线合理,生态完善。Vue 3.0的设计过程,让我看到了一个优秀的框架是如何权衡各种因素、不断演进的。
收获二:学会了用批判性的眼光看待新技术
以前我总是对新技术充满盲目崇拜,觉得新的就是好的,最新版本的一定比旧版本强。但是通过学习Vue 3.0的经历,我学会了用批判性的眼光看待新技术。
新技术不一定就比旧技术好,它可能解决了旧技术的一些问题,但是也可能引入新的问题。比如Vue 3.0的基于函数的API解决了mixins的问题,但是也带来了.value的不优雅和学习成本的增加。Proxy解决了Object.defineProperty的局限,但是也带来了浏览器兼容性的问题(虽然现代浏览器都支持Proxy,但是如果要兼容IE的话就不行了)。
所以,面对新技术,我们不应该盲目跟风,而应该理性地分析:它解决了什么问题?带来了什么新问题?升级的成本和收益是什么?现在是不是升级的好时机?想清楚这些问题之后,再决定要不要学、要不要用。
收获三:明白了"时机"的重要性
学习新技术,时机很重要。太早了,技术还不稳定,文档不完善,生态不成熟,学习成本高,学了也用不上;太晚了,别人都已经用上了,你还在学基础,就落后了。
最好的时机是技术刚刚稳定、生态开始成熟、有了比较完善的文档和教程的时候。这时候学习,成本比较低,而且学了之后很快就能在实际项目中用上,学用结合,掌握得更牢固。
Vue 3.0在2018年初的时候,显然还太早了,API都还没稳定。这时候去学,事倍功半。等它正式发布、API稳定、生态开始成熟之后再学,才是更好的时机。
这个道理不仅适用于Vue 3.0,也适用于所有的新技术。不要做最早的"吃螃蟹的人",除非你有特别的需求或者特别的兴趣。对大多数人来说,等技术稍微成熟一点再学,是更明智的选择。
收获四:夯实基础比追新更重要
在折腾Vue 3.0的过程中,我发现很多困惑其实是因为基础不够扎实。比如对响应式原理的理解不够深入,对JavaScript的Proxy、Reflect等新特性不够熟悉,对函数式编程的思想不够了解。如果这些基础足够扎实,学习Vue 3.0的新特性就会容易很多。
这让我意识到,夯实基础比追新更重要。框架和库会不断更新,今天学Vue 3.0,明天可能又有新的框架出来。但是基础的东西是不变的,比如JavaScript的核心概念、数据结构和算法、设计模式、浏览器原理、网络协议等。把这些基础打扎实了,不管框架怎么变,都能快速上手。
所以,从那之后,我不再花太多时间去追那些还不稳定的新技术,而是把更多的精力放在夯实基础上。基础扎实了,学什么都快。
五、对Vue 3.0的期待和建议
虽然我暂时"放弃"了学习Vue 3.0,但是我还是非常期待它的正式发布。作为一个Vue的重度用户,我希望Vue 3.0能越来越好。
期待一:API稳定之后,能有完善的文档和教程
文档和教程对新技术的推广非常重要。Vue 2.0的文档非常友好,这也是Vue能快速流行的重要原因。希望Vue 3.0正式发布之后,能有同样高质量的文档和教程,让新手也能快速上手。
特别是基于函数的API,是一个比较新的概念,很多人可能不太习惯。希望能有详细的指南和最佳实践,告诉大家怎么组织代码、怎么复用逻辑、怎么处理大型组件,让大家能更快地接受和使用新的API。
期待二:生态能尽快跟上
框架的生态非常重要。Vue 2.0的成功,很大程度上得益于它完善的生态。希望Vue 3.0正式发布之后,Vuex、Vue Router、Element UI等核心库能尽快适配,第三方组件库和工具也能尽快跟上,让大家能在实际项目中放心地使用Vue 3.0。
期待三:能有平滑的升级路径
从Vue 2.0升级到Vue 3.0,肯定会有一些breaking changes。希望Vue团队能提供一个平滑的升级路径,比如迁移工具、兼容层、详细的迁移指南等,让大家能比较顺利地从Vue 2.0升级到Vue 3.0,而不是必须重写整个项目。
期待四:保持Vue"简单易学"的优势
最后,也是最重要的一点,希望Vue 3.0能保持Vue"简单易学"的优势。虽然引入了很多新特性,但是希望不要让学习曲线变得太陡峭。新特性可以有,但是最好能有渐进式的学习路径,新手可以先用简单的方式上手,然后再慢慢学习高级特性。不要让Vue变成一个只有专家才能用的框架。
六、结语
我的"Vue 3.0前瞻从入门到放弃"的经历,到这里就讲完了。
回顾这段经历,我觉得"放弃"并不是一件坏事。在不合适的时机,选择暂时放弃,把精力放在更重要的事情上,是一种明智的选择。这不代表我不喜欢Vue 3.0了,也不代表我以后不会学了,只是我觉得现在还不是最好的时机。
等Vue 3.0正式发布、API稳定、生态成熟之后,我一定会重新开始学习,并且把它用到实际项目中。因为我相信,Vue 3.0会是一个非常优秀的框架,它会让前端开发变得更高效、更优雅。
最后想说的是,技术在不断发展,新的框架和库层出不穷。作为开发者,我们要保持学习的热情,但是也要有自己的判断,不要盲目跟风。选择适合自己的技术,在合适的时机学习,把基础打扎实,才是最重要的。
Vue 3.0,我们正式版见。
评论(0)
暂无评论,快来抢沙发~
评论功能仅对会员开放,请先登录
登录