• 开始时间:2019-03-01
  • 目标主要版本:3.x 版本
  • 引用 issue:N/A
  • 实现的 PR:N/A

摘要

通过尽可能多地通过命名的导出来暴露 API,使 Vue 运行时具有 tree-shakable。

基本范例

  1. import { nextTick, observable } from 'vue'
  2. nextTick(() => {})
  3. const obj = observable({})

动机

随着 Vue 的 API 增长,我们一直在努力平衡功能和包大小之间的权衡。我们希望将 Vue 的大小开销保持在最低水平,但是我们也不希望因为大小限制而限制其能力。

有了 ES 模块的静态分析的友好设计,现代 bundlers combined 和 minifiers 相结合,现在可以消除(eliminate) bundler 中任何没有使用 ES 模块导出的地方。我们可以重组 Vue 的全局和内部 API,以利用这一点,使用户只为他们实际使用的功能买单。

此外,由于知道可选功能不会增加不使用这些功能的用户的 bundler 大小,我们现在有更多的空间在核心功能包含可选功能。

具体设计

目前在 2.x 版本,所有的全局 API 都暴露在单个 Vue 对象上:

  1. import Vue from 'vue'
  2. Vue.nextTick(() => {})
  3. const obj = Vue.observable({})

在 3.x 版本,它们只能作为命名的 import 方式访问:

  1. import Vue, { nextTick, observable } from 'vue'
  2. Vue.nextTick // undefined
  3. nextTick(() => {})
  4. const obj = observable({})

通过不附加在 Vue 上默认导出所有 API,任何未使用的 API 都可以由支持 tree-shakable 的 bundle 产生的最终 bundler 中被丢弃。

受影响的 2.x API

  • Vue.nextTick
  • Vue.observable
  • Vue.version
  • Vue.compile(only in full builds)
  • Vue.set(only in compat builds)
  • Vue.delete(only in compat builds)

内置辅助 API

除了公共 API,很多内置组件和 helpers 也可以作为命名的导出物导出。这使得编译器可以输出只在使用的时候才导入的功能代码。例如下面的模版:

  1. <transition>
  2. <div v-show="ok">hello</div>
  3. </transition>

可以编译成一下内容(用于解释,不是准确的输出):

  1. import { h, Transition, applyDirectives, vShow } from 'vue'
  2. export function render() {
  3. return h(Transition, [
  4. applyDirectives(h('div', 'hello'), this, [vShow, this.ok])
  5. ])
  6. }

这意味着 transition 组件只在实际用到的时候才会被导入。

请注意,上述内容只适用于 ES 模块构建,用于 tree-shakable 功能的 bundlers 构建仍然包括所有功能,并且 Vue 全局变量上暴露所有内容(并且编译器将产出适当的输出,以使用全局上的 API,而不是导入)。

缺点

用户不能再导入一个单一的 Vue 变量,然后使用它的 API。然而,这应该是一个值得的权衡,因为可以使 bundler 的尺寸最小。

全局 API 在插件中的使用

一些插件可能依赖最初在 Vue 上公开的全局 API:

  1. const plugin = {
  2. install: Vue => {
  3. Vue.nextTick(() => {
  4. // ...
  5. })
  6. }
  7. }

在 Vue3.0 中,它们需要明确地导入这些东西:

  1. import { nextTick } from 'vue'
  2. const plugin = {
  3. install: app => {
  4. nextTick(() => {
  5. // ...
  6. })
  7. }
  8. }

这产生了一些开销(overhead),因为它要求库的作者在他们的构建设置中正确配置 Vue 的外部化:

  • Vue 不应该绑定在库中;
  • 对于模块构建,import 应该被搁置,由最终的用户 bundler 来处理;
  • 对于 UMD 或者浏览器构建,应该先尝试全局的 Vue.h,然后回到 require 调用。

这是 React 库中常见的做法,webpack 和 Rollup 都可以做到这一点。相当数量的 Vue 库也已经做到了。我们只需要提供适当的文档和工具支持。

备选方案

N/A

采纳策略

作为迁移工具的一部分,应该可以提供一个代码 mod。

没有解决的问题

N/A