Vue.js 3.x 源码解析先导

17,020 阅读12分钟

前言

2018 年 6 月我在慕课网发布了 Vue.js 2.x 的源码解析课程 《Vue.js 源码全方位深入解析》,同时也开源了课程配套电子书。时隔一年多,Vue 官方也开源了 Vue.js 3.x,那么在不久的将来,我也会系统化地做 Vue.js 3.x 的源码分析,同时更新我的这门课程视频以及电子书。

Vue.js 3.x 源码刚开源不久,很多人都非常兴奋,我也不例外。我写下这篇文章作为 Vue.js 3.x 源码解析课程的先导片,和大家聊聊我对 Vue.js 源码的一些感悟。

聊聊 Vue.js 3.x

Vue.js 3.x 目前的状态

Vue.js 3.x 目前处于 Pre-Alpha 的状态,从 Vue 官方的 Roadmap 来看,2019 年 Q3 结束前开源 Vue 3.x 的源码,Q4 除了继续完善 Vue.js 核心源码之外,还要补齐周边的生态建设:如 vue-routervuexvue-cliVue DevtoolsJSX 等,在 Q4 结束前才会发布 Alpha 版本。但是 Alpha 版本也只是内部测试版本,之后还要经历 Beta 对外测试版本,RC 候选发布版本、最后才会到正式的 Realase 版本,所以距离大家在生产环境投入使用还有很长的时间。那么这段时间,对于 Vue.js 3.x 我可以做哪些事情呢。

Vue.js RFC

Vue.js 官方设立 RFC 的初衷是为了让 Vue.js 本身的开发流程更加规范化,当有一个新功能的想法出现,会先发布一份 RFC 的提案,由社区在一起讨论,当提案通过后再去开发实现。

Vue.js 3.x 在开发之前也发布了多份 RFC 提案,其中讨论比较多的是 Vue.js 3.x 关于组件的写法,由最初的 Class-API 提案被废弃到之后热烈讨论的 Function-based component API,再到最后确认的基于 Function-based component API 修订的 Composition API,经历了很长一段的时间,期间社区出现了不少反对的声音,比如 “和 React 更像了,为啥我不直接用 React”、“Class API 更好”、“Vue.js 变得一点都不简单了” 等等,官方都做了很好的回应,因此学习 Vue.js 3.x,你应该先去学习这份 RFC

通过这份 RFC 的学习,你会大致了解 Vue.js 3.x 组件的写法、详细设计、甚至是一些”缺点“。Vue.js 3.x 摒弃了 2.x Options API,拥抱了 Composition API,为了更好的逻辑复用、代码组织以及更好的类型推导。

Vue.js 3.x 尝鲜

Vue.js 3.x 源码已经开放,虽然没有发布,但是我们可以 clone 下来,安装好相关依赖,构建一份打包后的代码为自己所用。

在阅读完 Composition API 的 RFC 后,我们已经对 Vue.js 3.x 组件的写法有了一定了解,并且 2.x 的大部分 feature 3.x 都已经支持,我们用 3.x 写一个简单的 demo 问题应该不大。我前段时间就基于 Vue 3.x 写了一个 todomvc 的 demo,感兴趣的同学可以去 GitHub clone 下来跑跑看看。

在写 demo 的时候我还遇到了 v-model 实现的坑,对源码一番调试后大致定位了原因,不过由于牵涉到核心的改动会比较多,所以我和尤大反馈了一下(微信提 issue),官方很快就修复了这个问题。

Vue.js 3.x 源码

Vue.js 3.x 源码放出来的第二天,社区就有出来源码分析的文章,不过看了好几篇都是在分析 Reactive 相关的 API,给人的错觉好像 Vue 只有响应式一样,甚至还有某些培训机构也跟着蹭起了热度。有些文章写的还是很不错的,比如我记得掘金有一篇是教大家从单测看起,确实是一个很好的学习源码的思路,但还有几篇也未免有蹭热度之嫌。对我而言,除了 Reactive,我更愿意去关注 Setup 函数的初始化逻辑、Compile 过程的优化、Render 写法的变化、以及 Patch 过程的优化。

Vue.js 3.x 源码采用了 monorepo 的管理方式,采用 TypeScript 编写,对于 Vue.js 的开发者而言,这种方式是更易于维护源码的。如果你想学习 Vue.js 3.x 的源码,首先你得学会 TypeScript。

对于大部分人而言,现在去看 Vue.js 3.x 的源码还为时过早了,主要是你现在还用不到,我之前在掘金发布过一篇文章来聊聊源码学习,现在还不是学习 Vue.js 3.x 源码的好时机。

但是如果你是一个对技术非常有热情的人,在早期去学习 Vue.js 3.x 源码,甚至去参与 Vue.js 3.x 的开发共建,对自己的技术提升还是有很大帮助的。

Vue.js 2.x 源码过时了吗

Vue.js 3.x 源码开放了,很多小伙伴不免担心,我现在学习 Vue.js 2.x 的源码过时了吗?

成熟稳定的 Vue.js 2.x

Vue.js 2.x 从 16 年底发布距今已接近 3 年,有无数大厂已经使用 Vue.js 重构和开发项目,Vue.js 2.x 的 npm 下载量每月有 90 多万,Jsdelivr CDN 每月有 5 亿次引用,Chrome DevTools 每周有 90 万的活跃用户。如此庞大的用户量足以说明 Vue.js 是一个非常靠谱和成熟的框架,另外官网对 Issue、Pull Request 的响应也是比较快的,除了高达 97% 的单元测试之外,官方还尝试做了一些回归测试

我们知道 Vue.js 是一个渐进式框架,除了官方提供的一些生态插件 vue-routervuexvue-cli 之外,社区还有非常多的优秀的轮子如 element-uicube-uivue-lazyloadvue-i18n 等,这些插件能很好地辅助我们平时的业务开发。

升级的成本

Vue .js 2.x -> Vue.js 3.x 升级还是有一定的成本的,虽然说官方会出一个保留 Options API 的写法的版本,但是未免还会有一些 breaking change 的,比如手写 render 函数部分语法就已经发生了改变,模板写法也会发生一些变化。未来应该会出一个代码升级的指南,甚至会用工具帮我们做一部分工作,但是大规模的产线项目做核心框架升级,还是有相当大的成本和风险的。

如果你的业务代码升级到 Vue.js 3.x,也就意味着你依赖的生态插件也需要升级到 Vue.js 3.x,比如 element-ui 这种大型项目,升级起来也是有相当大的工作量的,所以你需要先等到你依赖的生态插件升级到 Vue.js 3.x 并且稳定后,你才能考虑在你的业务中做框架升级。

Vue.js 1.x -> Vue.js 2.x 的升级似乎没有那么麻烦,那是因为 Vue.js 1.x 的时候用户规模还很小,生态也没有起来,甚至很多公司直接上手的 Vue.js 2.x,并没有历史包袱。

痛点

Vue.js 1.x -> Vue.js 2.x 的升级变化还是很明显的,虚拟 DOM 在 Vue.js 2.x 中得以实现,它让服务端渲染、跨端渲染成为可能。我们来看一下 Vue.js 3.x 的设计目标:更小、更快、加强 TypeScript 支持、加强 API 设计一致性、提升自身可维护性、开放更多的底层功能。对大部分用户而言,更小更快是一个吸引点,对于 TypeScript 用户而言,加强 TypeScript 支持是一个吸引点,但是这些能解决开发中的痛点么?

除非 Vue.js 3.x 能解决 Vue.js 2.x 开发中的痛点(比如我这个项目有性能瓶颈,性能的提升能帮助我解决这个性能瓶颈),否则重构的成本和它来带来的收益就是一个需要权衡的问题。另外考虑到 Vue.js 3.x 用了一些 ES6 的新特性如 Proxy,在浏览器兼容性这块也是需要考虑的。

老板通常是不会允许你做这种纯技术重构的,如果你想用 Vue.js 3.x 做重构,一定要抓到痛点,把重构的收益和老板说清楚。

虽然老项目用 Vue.js 3.x 重构会有很大的成本和风险,我们也可以在一些非核心的新项目中去尝试新技术,当然这一切也是需要等待 Vue.js 3.x 正式发布以及依赖的 Vue 插件都更新支持 Vue.js 3.x 才可以。

结论

Vue.js 3.x 想全面替代 Vue.js 2.x 需要有相当长的路要走,未来相当长一段时间 Vue.js 2.x 仍然是主流,Vue.js 2.x 的源码学习并没有过时,如果你是一个 Vue.js 2.x 的使用者,就应该去学习 Vue.js 2.x 的源码。

我应该学习源码吗

很多人都有困惑,我会使用不就行了吗,为什么还要学习源码呢?

学习源码的好处

学习是为了更好的工作,工作中难免会遇到一些问题,学习源码最直接的好处是能帮你直接定位问题的根本原因,从而帮助你解决问题。很多人抱怨加班多,不妨问问自己,有多少时间是在写业务,多少时间是在写(找) bug。快速定位问题解决 bug,可以有效地提升你的工作效率,很可能就不用加班了,甚至会多出学习的时间,形成一个良性循环。

学习源码可以很好地巩固基础,修炼内功,提升技术。前端几乎都会学习 JS 的基础知识,如类型、变量、函数、作用域、闭包、原型链、event loop 等知识,但很多人很难把这些知识在实践中运用自如,主要原因还是实践的少了,大部分时间都在写业务的胶水代码。学习 Vue.js 这类框架的源码,会不断去巩固这些知识点,如果你源码看熟练了,那么你的 JS 基础就会更扎实。

学习源码有助于你更好地理解所用的技术栈,更熟练地在工作中运用。比如你深入学习了 Vue.js 的核心源码,你会理解 Vue.js 框架产生的意义、Vue.js 的职责边界、数据驱动的本质;你还会知道如何实现的组件化,在什么生命周期应该做什么事情,如何编写 Vue.js 的插件,如何和其它第三方 JS 库深度结合。你再也不会问“如何用 Vue 实现 XXX” 的傻问题了。

学习源码可以让我们站在巨人的肩膀上,Vue.js 这么优秀,尤大也是参考了很多其他优秀源码的实现,比如 Vue.js 2.x Virtual DOM 部分参考了 snabbdom,Vue.js 3.x Reactive 的实现参考了Meteor Trackersalesforce/observable-membrane 等。我们在阅读的源码的时候,也可以把源码中的优秀的设计思想、代码实现吸纳到我们平时的开发工作中。

学习源码还有一个偏功利的作用,应付面试。越来越多的公司在面试环节会考察候选人对所用技术栈实现原理的考察,主要目的还是考察候选人的技术能力以及技术热情和追求,因为通常对技术热爱的人通常都会保持技术好奇,乐于探究所用到的技术栈的实现原理。但是往往以这个目的去学习源码的同学是学不好的,对源码的理解很浅,甚至出现了死记硬背的情况。所以学习好源码可以帮助我们在面试中应答自如,但是我们不应该为了面试去学习源码。

学源码的时机

通常我们去学习一个技术栈的源码的时机是在我们对他的使用已经很熟练的情况,比如你是一个 Vue.js 的一年以上经验的使用者,那么你已经可以去学习它的源码了,这时候你的学习应该是系统化地学习。

当你工作中使用某一个新框架的时候遇到一个奇怪的问题,通过查阅文档也未能解决,这个时候你也可以去看源码,当然这个时候并不需要系统地去学习,只需要把和你问题相关的源码理解了,找到问题即可。当然想达到这一步就需要你有快速阅读源码定位问题的能力,这个能力也是在你不断去阅读大量优秀源码过程中锻炼的。

学不动了怎么办

源码学习的好处我们已经介绍了很多,但是源码学习的本身是枯燥的,抽象的,它没有直观酷炫的效果,学习起来费脑子,是很多人直呼学不动的原因。

其实学不动的主要原因还是因为没掌握好的学习方法,好的方法能让你事半功倍,正如我在来聊聊源码学习 文章中提到的几个方法,全盘了解、问题驱动、主线优先、参与共建、阅读技巧、辅助资料。除了这些方法,根据我源码课程中一些学的不错的同学的经验,自己在学习的过程中多记笔记,多在课程问答区提问,甚至最后自己产出源码分析系列文章,都能非常好的辅助学习源码。其实做这些事情都是不断在帮助自己建立自信和成就感,激发学习兴趣,把无趣的事情变得有趣和有意义。

课程后续计划

源码课程会等待 Vue.js 3.x 发布正式版本且稳定后会开始准备重新录制,仍然是电子书和视频的方式。

重新录制的源码课程不仅仅会讲清楚源码实现流程,还会多加入一些使用场景、设计原因的分析。

翻新课程是在原课程的基础上增加 Vue.js 3.x 的章节,已购买课程的同学可以继续学习,无需购买新课程。

先学会用再学原理,因此在 Vue.js 3.x 正式发布后,我会优先重新录制 《Vue2.0开发企业级移动端音乐Web App》课程,同样是免费升级喔。

音乐课程 + 源码课程的重新录制,是我明年的主要计划,暂无计划出新课程了。除了版本的升级,我会像《Vue.js2.5 + cube-ui重构饿了么App》升级课程那样尽量往课程中加入一些新东西的,敬请期待~