12 月 10 日,第五届 Vue.js 开发者大会(VueConf 2022)由 Vue.js 官方通过在线直播的方式举办。Vue.js 作者尤雨溪发表了题为 《Vue 的进化历程》 的演讲,下面就来看看这场演讲的具体内容吧!
库阶段
2013-2015年,可以看做是 Vue 的库阶段。那库和框架的区别到底是什么?库更多的是嵌入到已有的体系,只是拿开简单使用。而框架会定义更加广泛的一套工程实践,遵循一定的最佳实践,用配套的工具去遵循一套完整的规范。所以当时的 Vue 只是一个库。
库阶段的重要里程碑:
2013.12:发布第一个以“Vue.js”命名的版本(0.6.0),在此之前的版本都叫 Seed;
2014.02:第一次在 HackerNews 上公开发,公开后的第一周获得了 400+ Github Star;
2014.10:第一次实现 Vue SFC 单文件组件(vueify),使用 Browserify 打包;
2014.11:第一次完全重写(0.11),考虑如何让它更适合用在生产环境中。
库阶段的设计重点:
- 基于 ES5 的 getter/setters 和原生 JavaScript 对象实现响应式系统,当时的设计重点就是满足个人设计和实现上的想法和兴趣;
- 基于响应式系统实现模版数据绑定(MVVM);
- 设计重点就是能像 JQuery 一样可以直接通过<script>标签直接引用的简单库,这种方式不会对其他方面产生意见和限制。
库阶段的特征:
- Vue 还不算一个框架;
- 当时的 API 受到了 Backbone/Ractive 的影响:
响应式系统和组件实例有很强的耦合,所有响应式的内容都需要通过在this上做操作来实现,这样的实现比较直观,容易理解,符合基于class思考的思维模式,但是会影响逻辑复用;
直到 0.11 版本才引入 Mixins(混入);
- 该阶段还在摸索完善模板语法和作用域规则,每个版本的模板语法都会有比较重大的变动,并且作用域规则不是很明确;
- 基于 DOM 的渲染机制:
- 模板和编译后的 JavaScript 之间没有对应性,当时的 Vue 并没有“编译”过程;
- 当时的 Vue 的实现通过把模板直接实例化为 DOM 树;
- 遍历实例化之后的 DOM 树,在遍历过程中实现数据绑定;
- 类似于现在 petite-vue 的实现,它是在 Vue 3 之后,重新将 Vue 1 的实现构成一个更轻量的实现,可以将 petite-vue 认为是 Vue 1的一个新的展现, 把 Vue 1 的实现以更现代的方式去提供出来,其更适用于更轻量化的、不需要很多工程化介入的场景。
框架阶段
2015-2016 年,Vue 就进入了框架阶段,以 1.X 版本为目标。
框架阶段的重要里程碑:
- 2015.08:发布第一版 Vue Router;
- 2015.09:基于0.11、0.12版本开始开发 Vue 1.0,主要是完善模板语法;
- 2015.10.26:发布 Vue 1.0,代号为 Evangelion;
- 2015.12:发布第一版 vue-cli,它更像是一个拉模板的工具,将配置好的模板拉到本地;
- 2016.03:发布第一版 Vuex。
框架阶段的设计重点:
- 稳定模板语法和作用域的设计:
确定了 v-bind、v-on 和对应简写的语法;
第一次引入了 v-for(取代了 v-repeat);
- 将 Vue 项目的涵盖范畴扩大到了单页面应用(SPA)框架
- SPA 路由;
- 状态管理;
- 工具链:实现了单文件组件的热更新支持和Scoped CSS。
通用框架阶段
2016-2019年,Vue 进入了通用框架阶段。
通用框架阶段的重要里程碑:
- 2016.03:第一次明确提出“渐进式框架”的概念;
- 2016.04:开始开发 Vue 2.0,尤雨溪正式离职开始全职开发 Vue;
- 2016.10.01:发布 Vue 2.0,代号为 Ghost in the Shell;
- 2016.11:发布 Vue 2.1,代号为 Hunter X Hunter,引入了作用域插槽;
- 2017.02:发布 Vue 2.2,代号为 Initial D,SSR 支持基于路由的代码分割,每个路由的代码可以懒加载;
- 2017.04:发布 Vue 2.3,代号为 JoJo,SSR 支持基于路由的资源预加载;
- 2017.06:发布 Vue 2.4,代号为 Kill la Kill,SSR 完整异步组件支持,可以在 SSR 应用的任何地方使用异步组件,引入了部分优化的 SSR 编译输出;
- 2018.01-08:开发 Vue Cli 3.0,进一步扩展框架的边界,将工具链视为框架的一部分;实现针对 SPA 的高度集成的工具链,有插件机制,开箱即用,集成 TypeScript 、单元测试、ESLint 等;
Vue 2.0 阶段的设计重点:
- Vue 的第二次彻底重写,目标是改进代码的架构,提高其长期的可维护性,目前来看 2.0 版本的可维护性依然是相当可以的;
- 引入了将模板编译为 Virtual DOM 渲染函数的编译流程,也就是在 2.0 才引入了“模板编译”的概念;
- 基于 Virtual DOM 的服务端渲染(SSR),先编译为 Virtual DOM 的渲染函数,生成 Virtual DOM,再将 Virtual DOM 字符串化,类似于 React 的服务端渲染;
- 基于 Virtual DOM 的 跨端渲染(整合 Weex,NativeScript);
- 结合类型系统:
在源码中使用 Flow 定义类型;
直到现在,2.x 版本的 TypeScript 类型定义都需要手动维护,而不是从源代码中生成的,这也是在 Vue 3 中使用 TypeScript 进行重写的原因之一。
这个阶段的一个重要 demo 就是:vue-hackernews-2.0[1],在当时这个 demo 有重要的意义:
- 使用 Webpack + SFC + Vue Router + Vuex + SSR 实现;
- 第一个完整展示 Vue 2 SSR 架构的 demo,包含了相关的 Webpack 配置,单文件组件如何针对客户端和服务端进行不同的编译配置,如何在重构的架构中使用路由、状态管理等;
- 利用这个 demo 做了很多 Vue 2 SSR 功能的开发,通过这个 demo 来测 Vue 2 SSR 在实际开发中是否易用;
- 这个 demo 更重要的意义是启发了上层的 SSR 框架,比如 Nuxt.js,Nuxt 最初就参照这个 demo 实现,并吸取了 Next.js 的经验。
编译/运行时混合阶段
2019年至今,Vue 进入了编译/运行时混合阶段。虽然 2.0 阶段引入了编译,但是 2.0 的编译和运行时的结合是非常浅的结合,编译器编译出 Virtual DOM 渲染函数就到此为止了,编译器对运行时是怎么样的并没有太多概念,而运行时对于编译器也是没有概念的,这样很多优化空间就被浪费了。所以 3.0 阶段的主要目标就是让编译器和运行时都属于框架的一部分,它们本身就是耦合的。 在耦合的前提下,让编译器为运行时提供更多的信息,让运行时知道编译器提供的信息。
编译/运行时混合阶段的重要里程碑:
- 2018.09:在 Vue.js London 宣布 Vue 3 的开发计划;
- 2018.09 - 2019.05:调研阶段;
- 2019.05:实现基于编译优化 Virtual DOM 性能的新策略;
- 2019.08:提出 Composition API RFC;
- 2020.01:发布 Vue 3.0 alpha 版本;
- 2020.04:发布 Vue 3.0 beta 版本,引入了完全优化的 SSR 编译输出,如果组件是用模板写的,那它的 SSR 编译输出不存在任何 Virtual DOM 的开销,所有能做成字符串拼接的地方都做成了字符串拼接;
- 2020.04 - 2021.02:绕道开发了 Vite。
- 2020.09:Vue 3.0 稳定版正式发布;
- 2021.06:发布 Vue 3.1 版本,提供 Migration Build,使用可以兼容 Vue 2 的用法让用户更方便的升级;
- 2021.08:发布 Vue 3.2 版本,引入了 <script setup>。
- 2022.01:Vue 3 正式切换为默认版本,此时 Vue 3 框架范畴内的工具都准备完毕;
- 2022.02:发布全新的 Vue 3 文档;
Vue 3.0 重构初期的重心如下:
- 提高浏览器的最低支持要求,使用现代 ES 语法和功能;
- 全面提升系统;
- 改善类型系统的整合;
- 改善在大型应用中的可扩展性。2018年慢慢开始有有较大型企业、项目开始使用Vue,让 Vue 遇到了新的挑战,在实际的场景中,之前的 Vue 设计在比较大的团队协作的场景中存在可维护性上的问题,希望在 Vue 3 中找到这些问题的解决方案。
Composition API 的意义:
- Vue 的用例越来越多地进入企业、大型项目领域;
- Options API 在可扩展性方面有明显的上限,对于重构庞大、臃肿的组件有很大的难度,不能轻松的进行逻辑的重新组织。而 Composition API 对逻辑的可维护、组合、复用提供了很好的解决方案;
- 因为 Composition API 更多的依赖函数调用,所以对类型系统更友好;
- 提供灵活且可维护的逻辑组合/复用。
Vite 的意义:
- Vite 大幅优化了开发体验;
- 将和框架没有耦合的工具链职责剥离,交给一个更大的社区去维护,这样也会样 Vue 的体验变得更好;
- 减少 Vue 本身的框架范畴和维护负担:Vue CLI -> create-vue
Vue 3 目前定义的框架范畴:
- 核心(编译器 + 运行时)
- 文档
- 工具链(create-vue)
- SPA 路由(React Router)
- 状态管理(Pinia)
- 浏览器开发工具(vue-devtools)
- IDE 支持(Valar)
- TypeScript 支持(vue-tsc)
- 静态分析(eslint-plugin-vue)
- 单元测试(@vue/test-utils)
整体趋势就是向编译/运行时混合模式进化:
- 同一份模板,不有得编译输出:
在浏览器中:输出高度优化的 Virtual DOM 渲染函数;
在 SSR 中:输出 buffer + 字符串拼接;
将来:Vapar mode(不依赖 Virtual DOM 的渲染代码,获得更好的性能)
- 在单文件组件中引入更多的语法糖:
- <script setup>;
- v-bind():实现动态 CSS 的绑定;
- Reactivity Transform;
现状
- 社区现在仍然处于 2 -> 3 的过渡阶段;
- 2022年6月发布了 Vue 2.7,进一步弥补了 2 和 3 之间的断层,提供了一个 2->3 更缓和的升级流程。不过,如果现在的 Vue 2 项目很稳定,没必要为了升级而升级;
- 基于目前的 npm 数据:超过 30% 的项目在使用 Vue 3,大概 25% 的项目在使用 Vue 2.7,所以有超过一半的项目已经可以使用 Composition API 和<script setup>,整体的过渡情况比较乐观。
展望
Vue 团队接下来的工作会以 API 的稳定性为优先,重点会放在不影响使用方式的改进上。不计划引入像 React Server Components 这样需要和服务器强绑定的特性。
- 短期:
稳定 Reactivity Transform / Suspense,从实验特性变为稳定特性;
Vue 3.3 的重点是 SSR 的水合性能改进,提供以异步组件为边界的懒水合和按需水合。
- 中到长期:
- Vapor mode(受 Solid 启发的模板编译策略),明年 Vue 团队会更新更多相关信息。
关于 Vapor mode:
完全一样的模板/组件语法可以编译成完全不一样的输出,这个输出不再依赖 Virtual DOM 运行时,而是针对 Web 性能进行特化,可以提供极致的性能和内存占用,还可以在一些情况下做零成本组件抽象,即当组件只使用了基本的 API 时,将它编译成一个不需要组件实例的状态,这样就可以节省一定的组件实例开销。
Vapor mode 的使用方式上,可以将它无缝嵌入到现有的应用中,可以兼容基于 Virtual DOM 的第三方库。如果是全新的项目,可以启用 Vapor-only,这样就再兼容 Virtual DOM,丢掉了相关的运行时,适合对性能有极致要求的场景。
相关资料
[1] vue-hackernews-2.0: https://github.com/vuejs/vue-hackernews-2.0