乐趣区

预计今年发布的Vue3.0到底有什么不一样的地方?

还有几个月距离 vue2 的首次发布就满 3 年了,而 vue 的作者尤雨溪也在去年年末发布了关于 vue3.0 的计划,如果不出意外,我们将在今年的某个时间点见证 Vue3.0 的发布,虽然前几天在《StateOfJS: 2018 年 JavaScript 生态圈趋势报告》一文中我们看到目前 Vue 的使用者比 React 还少了不少,但在 Github 上 Vue 的 star 数已经超越 React,可见用户对 Vue 的喜爱,那即将发布的 Vue3 又有什么新特性呢?我们一起来看看吧!
Vue 3.0 已经在原型设计阶段了,而且我们已经实现了一个与 2.0 的特性近乎相等的运行时了。下文中列出的许多条目,要么已经实现了,要么已经确认可实现。那些还未实现或者仍在探索阶段的条目会用一个“*”标记

性能提升
一句话简介:更小巧,更快速;支持摇树优化;支持 Fragments 和跨组件渲染;支持自定义渲染器。
更小巧:这份新的代码库在设计之初就考虑到了对“摇树优化 (tree-shaking)”的友好。那些如内置组件 (<transition>、<keep-alive>)、运行时工具性指令(v-model)等特性将变为按需导入,所以也是“可摇树的”。对于这个新的运行时,它的大小将永远保持在 10kb 之下。另外,使这些特性变为“可摇树的”后,我们就可以提供更多的内置特性,同时还不会增加网络负载——如果没使用到这些特性的话。
摇树优化,是一种在打包时去除没用到的代码的优化手段,谷歌有一篇教程可以了解下: Reduce JavaScript Payloads with Tree Shaking

更快:在前期的基准测试中,我们看到整体性能有了一倍的提升,包括虚拟 DOM 的挂载和打补丁 (patching,指更新——译注) 的速度(我们从 Inferno 那里学了好些个技巧过来——Inferno 是目前速度最快的虚拟 DOM 实现),以及组件实例化速度和数据监测的性能。在 3.0 中,你应用的启动时间将缩减一半。
支持 Fragments 和 Portal:虽然体积更小了,但 3.0 还将内置对 Fragments (即允许组件拥有多个根节点) 和 Portal (即允许在 DOM 的其他位置进行渲染,而不是组件内部) 的支持。

关于 Portal,你可以将其理解为跨组件渲染或者异地渲染,vue-portal 是一个第三方实现,可以了解一下;Fragments 特性也有一个第三方库,但译者认为这个库的内部实现不够完善,叫做 vue-fragments,感兴趣可以了解一下。

增强的 slot 机制:所有由编译器生成的 slot 都将是函数形式,并且在子组件的 render 函数被调用过程中才被调用 (译注:现在只有 scoped slot 才是函数形式,其渲染的时机也是在父组件的渲染进行时)。这使得 slot 中的依赖项 ( 即数据——译注) 将被作为子组件的依赖项,而不是现在的父组件;从而意味着:1)当 slot 的内容发生变动时,只有子组件会被重新渲染;2)当父组件重新渲染时,如果子组件的内容未发生变动,子组件就没必要重新渲染。这种机制的改变,可以提供更精确的变动探测,也就可以消除没必要的重渲染。
支持自定义渲染器 (Renderer):这个 API 可以用来创建自定义的渲染器,它将作为“一等公民”出现,到时不再需要 fork 一份 Vue 的代码来通过修改实现自定义。这个 API 的到来,将使得那些如 Weex 和 NativeScript 的“渲染为原生应用”的项目保持与 Vue 的同步更新变得更加容易。除此之外,还将使得那些为了各种用途而创建自定义渲染器变得极其容易。

编译器相关的提升 *

如果采用的是支持“摇树优化”的打包器,模板中使用到的那些可选特性,在生成的代码中将通过 ES 的模块语法导入;而在打包后的文件中,那些没用到的可选特性就会被“摇掉”。
由于新的虚拟 DOM 实现所带来的提升,我们可以执行一些更加高效的编译耗时优化,如静态树提升 (static tree hoisting)、静态属性提升 (static props hoisting);以及为运行时提供一些来自编译器的提示,以此避开子组件的规范过程 (children normalization);提供 VNode 快速创建路径;等等。
我们计划对解析器进行重写,以便在对模板进行编译发生错误时,可以提供错误发生的位置信息;除此之外还可以带来对模板的 source map 支持;还可以支持第三方工具如 eslint-plugin-vue 和 IDE 的语言服务 (language services) 特性。

API 变动
一句话介绍:除渲染函数 API 和 scoped-slot 语法之外,其余均保持不变或者将通过另外构建一个兼容包来兼容 2.x。

模板语法的 99% 将保持不变。除了 scoped slot 语法可能会有一些微调之外,我们还没有任何其他针对模板的变动计划。
3.0 版本将原生地支持基于 class 的组件,而且无需借助任何编译及各种 stage 阶段的特性,以此提供良好的编写体验。许多现有的 (组件) 配置项将有对应的合理的 class 版本的 API。各种 stage 阶段的特性,如 class 的静态字段和装饰器 (decorator) 等仍然可以选择性地使用,以此增强编写体验。另外,整体的 API 在设计时也将考虑 TypeScript 的类型推断特性。3.x 的代码库本身将用 TypeScript 来编写,并提供增强的 TypeScript 支持。(就是说,TypeScript 的使用与否仍然是整体可选的)
2.x 系列的基于对象的组件格式仍将受支持,不过会在内部将其转换为一个相应的 class。
仍然支持 Mixins。*
为了避免在安装插件时造成对 Vue 的运行时的修改,顶层 API 可能会做一个大的翻修。到时,插件的作用域将只局限到具体的一个组件树,使得对那些依赖于某些具体插件的组件的测试变得容易,也会使得在同一个页面中挂载多个使用不同插件——但使用同一个 Vue 运行时——的 Vue 应用变为可能。*
函数式组件将支持纯函数的书写形式——不过,这样的话异步组件就需要通过一个辅助性函数来显式地创建了。
变动最大的部分将是渲染函数 (render) 中的虚拟 DOM 的格式。我们现在正在收集主流的第三方库的作者们的反馈,在对这些变动有了更多的信心之后,我们还会将更多的细节曝光;虽然变动较大,但是只要你没在你的应用中重度使用手写的渲染函数 (不是指 JSX),那么变动之后的升级应该会比较容易。

代码重构
一句话介绍:更优良的内部模块解耦;TypeScript;更易于贡献的代码库。
在从零开始编写 3.0 之初,“达到更加清晰和更易维护的架构,特别是为了让代码的贡献变得容易”就是我们的目标。为了对复杂性进行隔离,我们将一些内部功能拆分为了多个单独的包。例如,observer 模块将成为一个单独的包,拥有自己对外的 API 和自己的测试用例;不过请注意,这不会对框架级的 API 造成影响——你不需要另外手动从多个包里导入许多小件小件的模块就可以使用 Vue,相反 Vue 的最终包会事先装配好这些内部包。
另外,代码库现在改为了用 TypeScript 编写;虽然这会使得“熟练 TypeScript”成为对新代码库进行贡献的一个前置要求,不过我们相信有类型信息配合 IDE 的支持,对于一个新的贡献者来说,要做出有意义的贡献,实际上反而会更加容易。
将 observer 和 scheduler 解耦为分开的两个包后,我们还可以拿一些替代的实现对这两个包进行置换试验。例如,我们可以实现一个兼容 IE11、API 也相同的 observer;或者实现另外一种利用 requestIdleCallback 来在长耗时的更新中产出工作成果到浏览器的 scheduler。
重写虚拟 DOM (Virtual DOM Rewrite)
随着虚拟 DOM 重写,我们可以期待更多的 编译时(compile-time)提示来减少 运行时(runtime)开销。重写将包括更有效的代码来创建虚拟节点。

优化插槽生成 (Optimized Slots Generation)
在当前的 Vue 版本中,当父组件重新渲染时,其子组件也必须重新渲染(11 月 20 日更新:这句话是不严谨的,非常容易产生误导,我觉得有必要说明一下:2.0 组件的重新渲染就是组件粒度的,除非修改的数据是子组件的 props,才会触发子组件的重新渲染。引用自:https://juejin.im/pin/5bf28dd…)。使用 Vue 3,可以单独重新渲染父组件和子组件。
静态树提升 (Static Tree Hoisting)
使用静态树提升,这意味着 Vue 3 的编译器将能够检测到什么是静态组件,然后将其提升,从而降低了渲染成本。它将能够跳过未整个树结构打补丁的过程。
静态属性提升(Static Props Hoisting)
此外,我们可以期待静态属性提升,其中 Vue 3 将跳过不会改变节点的打补丁过程。
基于 Proxy 的观察者机制
目前,Vue 的反应系统是使用 Object.defineProperty 的 getter 和 setter。但是,Vue 3 将使用 ES2015 Proxy 作为其观察者机制。这消除了以前存在的警告,使速度加倍,并节省了一半的内存开销。
为了继续支持 IE11,Vue 3 将发布一个支持旧观察者机制和新 Proxy 版本的构建。
兼容 IE 11 *
一句话介绍:IE 11 将受到支持,但将会是另外构建一个版本 (build) 的形式支持,不过这个版本会存在与 Vue 2.x 响应式机制所存在的同样的局限。
新的代码库目前只针对主流浏览器,而且我们假定他们都支持 ES2015。但是,哎,我们也知道在可预见的未来还有很多用户仍然需要支持 IE11。除了 Proxy 外,大多数 ES2015 的特性都可以用转译或者垫片的方式在 IE11 中使用。我们的计划是另外单独实现一个具有同样 API 的替代性 observer,不过是基于老式的 Object.defineProperty API;然后再通过单独构建一个使用这个实现的 Vue 3.x 版本 (build) 进行发布,不过这个单独的版本还是会有 Vue 2.x 在变动探测方面所存在的问题,所以它其实并不是一个完全兼容 3.x 的一个版本。我们也意识到这会给第三方库的作者们带来某些不便,因为他们需要考虑两个不同版本之间的兼容性问题,不过当我们真的推进到那个阶段时,那时我们肯定会确保提供一份清晰的指导。
监测机制
一句话介绍:更加全面、精准、高效;更具可调试性的响应跟踪;以及可用来创建响应式对象的 API。
3.0 将带来一个基于 Proxy 的 observer 实现,它可以提供覆盖语言 (JavaScript——译注) 全范围的响应式能力,消除了当前 Vue 2 系列中基于 Object.defineProperty 所存在的一些局限,如:

对属性的添加、删除动作的监测
对数组基于下标的修改、对于 .length 修改的监测
对 Map、Set、WeakMap 和 WeakSet 的支持

另外这个新的 observer 还有以下特性:

公开的用于创建 observable (即响应式对象——译注) 的 API。这为小型到中型的应用提供了一种轻量级的、极其简单的跨组件状态管理解决方案。(译注:在这之前我们可以通过另外 new Vue({data : {…}}) 来创建这里所谓的 observable;另外,其实 vuex 内部也是用这种方式来实现的)
默认为惰性监测(Lazy Observation)。在 2.x 版本中,任何响应式数据,不管它的大小如何,都会在启动的时候被监测。如果你的数据量很大的话,在应用启动的时候,这就可能造成可观的性能消耗。而在 3.x 版本中,只有应用的初始可见部分所用到的数据会被监测,更不用说这种监测方案本身其实也是更加快的。
更精准的变动通知。举个例子:在 2.x 系列中,通过 Vue.set 强制添加一个新的属性,将导致所有依赖于这个对象的 watch 函数都会被执行一次;而在 3.x 中,只有依赖于这个具体属性的 watch 函数会被通知到。
不可变监测对象(Immutable observable):我们可以创建一个对象的“不可变”版本,以此来阻止对他的修改——包括他的嵌套属性,除非系统内部临时解除了这个限制。这种机制可以用来冻结传递到组件属性上的对象和处在 mutation 范围外的 Vuex 状态树。
更良好的可调试能力:通过使用新增的 renderTracked 和 renderTriggered 钩子,我们可以精确地追踪到一个组件发生重渲染的触发时机和完成时机,及其原因。

发布时间
不必太过担心,至少还能缓半年。
参考来源:Plans for the Next Iteration of Vue.js[[译] 尤雨溪:Vue 3.0 计划 ](https://juejin.im/post/5bb719…

退出移动版