原文链接: https://increment.com/frontend/making-vue-3
在过去的一年里,Vue 团队一直在研究 Vue.js 的下一个主要版本,我们希望在 2020 年上半年发布。这项工作在撰写本文时还在进行中),关于 Vue 新的主要版本的想法是在 2018 年底形成的,当时 Vue 2 的代码库大约有两年半的时间。在通用软件的生命周期中,这听起来可能并不长,但在这段时间内,前端的格局发生了翻天覆地的变化。
有两个关键的考虑因素促使我们对 Vue 进行了新的主要版本(和重写)。第一,主流浏览器中新的 JavaScript 语言功能的普遍存在。第二,当前代码库中暴露出来的设计和架构问题。
为什么要重写 利用新的语言功能随着 ES2015 的标准化,JavaScript(即 ECMAScript,缩写为 ES 的缩写)得到了重大改进,主流浏览器终于开始为这些新增加的功能提供了像样的支持。特别是一些新添加的功能为我们提供了极大的机会,使 Vue 的能力得到了极大的提升。
其中最值得一提的是 Proxy,它允许框架对对象进行拦截操作。Vue 的一个核心特性是能够监听用户定义状态的变化,并对 DOM 进行反应式更新。Vue 2 通过用 getter 和 setter 替换状态对象上的属性,实现了这种反应性。切换到 Proxy 可以让我们消除 Vue 现有的限制,比如无法检测到新的属性添加,并提供更好的性能。
然而,Proxy 是一个原生语言的功能,在传统的浏览器中无法完全复用。为了利用它,我们知道我们必须调整框架的浏览器支持范围--这是一个重大的突破性改变,只能在新的主要版本中提供。
解决架构问题在现有的代码库中修复这些问题,需要进行巨大的、危险的重构,几乎相当于重写。
在维护 Vue 2 的过程中,由于现有架构的限制,我们已经积累了很多问题,这些问题很难解决。例如,模板编译器的编写方式使得适当的源码映射支持变得非常具有挑战性。此外,虽然 Vue 2 在技术上可以构建针对非 DOM 平台的更高级别的渲染器,但我们不得不对代码库进行分叉,并重复了大量的代码来实现这一点。在当前的代码库中修复这些问题,将需要进行巨大的、危险的重构,几乎相当于重写。
同时,我们还以各种模块内部的隐式耦合形式积累了技术债务,以及似乎不属于任何地方的浮动代码。这使得我们很难孤立地理解代码库中的某一部分,而且我们注意到,贡献者很少有信心进行一些无关紧要的修改。重写将给我们提供了一个机会,让我们在考虑到这些问题的情况下重新思考代码组织。
初步原型设计阶段我们在 2018 年底开始了 Vue 3 的原型开发,初步目标是验证这些问题的解决方案。在这个阶段,我们主要集中在为进一步开发打下坚实的基础上。
切换到 typescriptVue 2 最初是用普通的 ES 编写的。在原型设计阶段后不久,我们意识到类型系统对于这样的项目来说是非常有帮助的。类型检查大大减少了在重构过程中引入意外 bug 的机会,并帮助贡献者更有信心地进行简单的修改。我们采用了 Facebook 的 Flow 类型检查器,因为它可以逐步添加到现有的纯 ES 项目中。Flow 在一定程度上起到了一定的帮助,但我们并没有如愿以偿地受益;特别是,不断的破坏性修改让升级成为一种痛苦。与 TypeScript 与 Visual Studio Code 的深度集成相比,对集成开发环境的支持也并不理想。
我们还注意到,用户越来越多地将 Vue 和 TypeScript 一起使用。为了支持他们的用例,我们不得不将 TypeScript 声明与源代码分开编写和维护,而源代码使用的是不同的类型系统。转换到 TypeScript 将使我们能够自动生成声明文件,减轻了维护负担。
内部包的解耦我们还采用了一个单体化的设置,框架由内部包组成,每个包都有自己的 API、类型定义和测试。我们希望让这些模块之间的依赖关系更加明确,让开发者更容易阅读、理解和修改。这对于我们努力降低项目的贡献障碍和提高项目的长期可维护性是非常关键的。
设置 RFC 流程到 2018 年年底,我们已经有了一个工作原型,有了新的反应式系统和虚拟 DOM 渲染器。我们已经验证了我们想做的内部架构改进,但只有面向公众的 API 改动的粗略草稿。现在是时候把它们变成具体的设计了。
我们知道我们必须尽早、谨慎地完成这项工作。Vue 的广泛使用意味着破坏性的改变可能会导致用户的大量迁移成本和潜在的生态系统碎片化。为了确保用户能够提供对打破性改动的反馈,我们在 2019 年初采用了 RFC(征求意见)流程。每个 RFC 都遵循一个模板,其中的章节集中在动机、设计细节、权衡和采用策略等方面。由于该流程是在 GitHub repo 中进行的,建议以拉动请求的形式提交,因此讨论在评论中有机地展开。