Vue 3.3更新回顾
一起来重温今年五月 Vue 3.3(代号"浪客剑心") 的升级大纲,为 Vue 3.4 预热前戏。
依赖更新
当升级到 Vue 3.3 时,建议同时更新以下依赖:
volar/vue-tsc@^1.6.4
vite@^4.3.5
@vitejs/plugin-vue@^4.2.0
vue-loader@^17.1.0(如果使用了 webpack/vue-cli)
Vue 3.3 版本速览
优化 + TS DX(开发体验)
支持宏中的导入类型和复杂类型
泛型组件
更符合人体工程学的 definedEmits
携带 definedSlots 的类型插槽
实验性功能
响应式 props 解构
defineModel
其他重要功能
defineOptions
更好地支持 getter 与 toRef 和 toValue 一起使用
支持 JSX 导入源
优化维护基建
优化 <script setup> + TS DX
支持宏中的导入类型和复杂类型
以前,defineProps 和 defineEmits 类型参数位置中使用的类型仅限于局部类型,并且能且仅能支持类型字面量和接口。这是因为,Vue 需要分析 props 接口上的属性,生成相应的运行时选项。
此限制现已被 Vue 3.3 解决。编译器现在可以解析导入类型,并支持一组有限的复杂类型:
import type { Props } from './foo'
// 导入 + 交叉类型
defineProps()
请注意,复杂类型支持基于 AST,因此无法 100% 全面支持。某些需要实际类型分析的复杂类型,比如支持条件类型,并无法支持。您可以对单个 props 的类型使用条件类型,但不能对整个 props 对象使用。
泛型组件
使用了 的组件现在可以通过 generic 属性接受泛型类型参数:
defineProps
items: T[]
selected:T
>}()
generic 的值与 TS 中 之间的参数列表完全相同。举个栗子,您可以使用多个参数、extends 约束、默认类型和引用导入类型:
import type { Item } from './types'
defineProps
id: T
list: U[]
}>
此功能以前需要显式选用,但现在最新版本的 volar/vue-tsc 默认启用。
更符合人体工程学的 definedEmits
以前,defineEmits 的类型参数能且仅能支持调用签名语法:
// 以前
const emit = defineEmits
(e: 'foo', id: number): void
(e: 'bar', name: string, ...rest: any[]): void
}>()
该类型匹配 emit 的返回类型,但有点冗长且难以编写。Vue 3.3 引入了一种更符合人体工程学的 emits 类型声明方式:
// 之后
const emit = defineEmits
foo: [id: number]
bar: [name: string, ...rest: any[]]
}>()
在类型字面量中,键是事件名称,值是指定额外参数的数组类型。尽管这不是必需的,但您可以使用标签元组元素来明确,如上所示。
调用签名语法仍然支持。
携带 definedSlots 的类型插槽
新的 defineSlots 宏可用于声明预期插槽及其各自的预期插槽 props:
defineSlots() 能且仅能接受类型参数,而不是运行时参数。类型参数应该是类型字面量,其中属性键是插槽名,值是插槽函数。函数的首参是插槽期望接收的 props,其类型将用于模板中的插槽 props。defineSlots 的返回值与 useSlots 返回的插槽对象相同。
目前的某些限制:
volar/vue-tsc 中尚未实现所需的插槽检查。
插槽函数返回类型目前被忽略,且可以是 any,但我们将来可能会利用它来检查插槽内容。
还有一个相应的 slots 选项供 defineComponent 使用。这两个 API 都没有运行时影响,纯粹用作 IDE 和 vue-tsc 的类型提示。
实验性功能
响应式 props 解构
响应式 props 解构以前是响应性转换(现已废弃)的一部分,现已被抽离为一个单独的功能。
该功能允许解构的 props 保留响应性,并提供更符合人体工程学的方式来声明 props 默认值:
此功能是实验性的,需要显式选用。
defineModel
以前,对于支持与 v-model 双向绑定的组件,它需要 :
声明一个 prop
在打算更新该 prop 时触发相应的 update:propName 事件:
Vue 3.3 通过新的 defineModel 宏简化了用法。该宏自动注册一个 prop,并返回一个可以直接变更的 ref:
此功能是实验性的,需要显式选用。
其他重要功能
defineOptions
新的 defineOptions 宏允许直接在 中声明组件选项,而不需要单独的 块:
更好地支持 getter 与 toRef 和 toValue 一起使用
toRef 已增强,支持将值/getter/现有 ref 标准化为 ref:
// 等价于 ref(1)
toRef(1)
// 创建一个只读 ref,它通过访问 .value 调用 getter
toRef(() => props.foo)
// 原样返回现有 ref
toRef(existingRef)
使用 getter 调用 toRef 与 computed 类似,但当 getter 仅执行属性访问而不进行昂贵的计算时,效率会更高。
新的 toValue 工具方法提供了相反的功能,将值/getter/ref 标准化为值:
toValue(1) // --> 1
toValue(ref(1)) // --> 1
toValue(() => 1) // --> 1
toValue 可以在组合式函数中代替 unref,以便您的组合式函数可以接受 getter 作为响应式数据源:
// 之前:分配不必要的中间 ref
useFeature(computed(() => props.foo))
useFeature(toRef(props, 'foo'))
// 之后:更高效精简
useFeature(() => props.foo)
toRef 和 toValue 之间的关系类似于 ref 和 unref 之间的关系,主要区别在于 getter 函数的特殊处理。
支持 JSX 导入源
目前,Vue 的类型自动注册全局 JSX 类型。这可能与其他需要 JSX 类型推断的库“梦幻联动”时产生冲突,尤其是 React。
从 Vue 3.3 开始,Vue 支持通过 TS 的 jsxImportSource 选项指定 JSX 命名空间。这允许用户根据其用例选择全局或每个文件选用。
为了向后兼容,Vue 3.3 仍然全局注册 JSX 命名空间。我们计划在 Vue 3.4 中移除默认的全局注册。如果您让 TSX 与 Vue “梦幻联动”,那么应在升级到 Vue 3.3 后将显式 jsxImportSource 添加到 tsconfig.json 中,避免在 Vue 3.4 中爆炸。
Vue 3.4更新
12 月 28 日,Vue 3.4 正式版发布,代号为“ Slam Dunk”,即灌篮高手。据尤大介绍,这个版本进行了许多重要的内部改进,其中最引人瞩目的是重写的模板解析器。新的解析器将速度提高了 2 倍,显著提升了整体性能。
此外,响应性系统也经过了重构,使得 effect 触发更为精确和高效。为了提升开发体验,还进行了一些 API 改进,包括 defineModel 的稳定以及绑定 props 时的新的同名简写。下面是本次版本更新的内容说明。
依赖项更新
功能亮点
解析器速度提高 2 倍,SFC 构建性能提升
更高效的响应式系统
defineModel 已稳定
v-bind 同名缩写
改进水合不匹配错误
错误代码和编译时标志参考
移除过时功能
全局 JSX 命名空间
其他已删除的功能
依赖项更新
为了充分发挥 Vue 3.4 版本的新功能,建议在升级至 3.4 版本时,同时更新以下依赖项,以避免重复:
Volar / vue-tsc@^1.8.27(必需)
@vitejs/plugin-vue@^5.0.0(如果使用 Vite)
nuxt@^3.9.0(如果使用 Nuxt)
vue-loader@^17.4.0(如果使用 webpack 或 vue-cli)
对于在 Vue 中使用 TSX 的情况,请检查 "Removed: Global JSX Namespace" 中所需的操作。
同时,请确保不再使用任何已弃用的功能。如果仍在使用已弃用功能,可能会在控制台中收到相应的警告。这些已弃用功能可能已在 3.4 版本中被移除。
功能亮点
解析器速度提高 2 倍,SFC 构建性能提升
在3.4版本中,Vue 团队进行了全面的模板解析器重写。之前,Vue采用了依赖大量正则表达式和前向搜索的递归下降解析器,而新的解析器则基于htmlparser2中的标记器,采用状态机的方式,只需要对整个模板字符串进行一次遍历。这样一来,无论模板大小如何,解析器的速度都提升了一倍。经过广泛的测试和生态系统的持续集成,新解析器对 Vue 最终用户来说是100%向后兼容的。
在整合新解析器与其他系统部分时,发现了一些可以进一步提高SFC编译性能的机会。基准测试显示,在生成 source map 时,编译 Vue SFC 的脚本和模板部分的速度提高了约44%。因此,使用 Vue SFC 的大多数项目在3.4版本中的构建速度应有所提升。但需要注意的是,Vue SFC 编译只是整个构建过程的一部分,与单独的基准测试相比,最终的端到端构建时间效益可能较小。
此外,新解析器不仅提升了 Vue 核心的性能,还对 Volar / vue-tsc 以及需要解析 Vue SFC 或模板的社区插件(如 Vue Macros)有性能提升的作用。
更高效的响应式系统
Vue 3.4 还对响应式系统进行了重大重构,目标是提高计算属性的重新计算效率。为了说明正在改进的内容,考虑以下场景:
此外,在3.4版本中:
多个计算依赖的变化只会触发同步 effect 一次。
数组的shift、unshift和splice方法只会触发同步 effect 一次。
除了在基准测试中显示的性能提升外,这些优化还可以在许多场景中减少不必要的组件重新渲染,同时保持完全向后兼容。
defineModel 已稳定
defineModel是一个新的宏,旨在简化支持v-model的组件的实现。它在 3.3 版本中作为实验性功能发布,并在 3.4 版本中升级为稳定状态。现在,它还提供更好的支持与v-model修饰符一起使用。
相关文档参考如下:
Revised Component v-model section
defineModel API reference
v-bind 同名缩写
现在可以缩写它:
改进水合不匹配错误
Vue 3.4 对水合不匹配错误消息进行了一些改进:
改进了措辞的清晰度(服务器渲染与客户端预期的区别)。
错误消息现在包括相关的DOM节点,这样可以快速在页面或元素面板中找到它。
水合不匹配检查现在还适用于class、style和其他动态绑定的属性。
此外,Vue 3.4 还新增了一个编译时标__VUE_PROD_HYDRATION_MISMATCH_DETAILS__,可以用于在生产环境中强制水合不匹配错误包含完整的详细信息。
错误代码和编译时标志参考
为了减小生产构建的打包大小,Vue 在生产环境中删除了长的错误消息字符串。然而,这也就意味着在生产环境中通过错误处理程序捕获的错误将只收到难以解读的短错误代码,需要深入研究 Vue 的源代码才能理解其含义。
为了改进这一点,Vue 团队在文档中新增了一个生产错误参考页面。该页面根据最新版本的 Vue 稳定发布自动生成错误代码,方便开发者进行参考。
此外,还添加了一个编译时标志参考,其中包含了如何在不同的构建工具中配置这些标志的说明。这样开发者可以根据自己的需求进行配置,以提高开发效率。
移除过时功能
全局 JSX 命名空间
自 3.4 版本起,Vue 不再默认注册全局 JSX 命名空间,以避免与 React 发生全局命名空间冲突,确保两个库的 TSX 可在同一项目中和谐共存。对于仅使用最新版 Volar 的 SFC 用户,此变更不会产生影响。
对于正在使用 TSX 的用户,官方提供了两个解决方案:
在升级至 3.4 之前,需要在 tsconfig.json 中明确设置 jsxImportSource 为 'vue'。此外,还可以在每个文件的顶部添加 /* @jsxImportSource vue */ 的注释,以文件为单位选择性采用此选项。
如果代码依赖于全局 JSX 命名空间的存在,例如使用 JSX.Element 等类型,可以通过显式引用 vue/jsx 来保持与 3.4 版本之前完全相同的全局行为,该行为会注册全局 JSX 命名空间。
需要注意的是,此次变更仅影响类型,且为次要版本中的重大变更,符合发布政策。
其他已删除的功能
在 3.3 版本中,Reactivity Transform 功能被标记为不推荐使用,并在 3.4 版本中被移除。由于该功能是实验性的,因此这个变化不需要进行重大更改。希望继续使用该功能的用户可以通过 Vue Macros 插件来实现。
在模板中使用 @vnodeXXX 事件监听器现在会导致编译错误,而不是发出不推荐使用的警告,需要改用 @vue:XXX 监听器。
v-is 指令已被移除。在 3.3 版本中,它被标记为不推荐使用,需要改用带有 vue: 前缀的 is 属性。
领取专属 10元无门槛券
私享最新 技术干货