返回文章索引
TRANSMISSION / MINT18 MIN READ

Vue 3.6 RC 升级全景:从 3.5 到 Vapor Mode 与 alien-signals

截至 Vue 3.6.0-rc.2,系统对比 Vue 3.5 与 3.6 的响应式内核、Vapor Mode、事件委托、互操作边界和渐进升级策略。

#Vue#JavaScript#前端工程
Vue 3.5 的虚拟 DOM 组件树经过晶体通道转向 Vue 3.6 的细粒度信号网络
Vue 3.6 RC 更像一次编译器与运行时的架构换挡,而不是一份新 API 清单

如果只看版本号,Vue 3.6 像是一次普通的次版本升级。但真正读完发布说明后,我的感受是:它更像 Vue 为下一阶段准备的一次“换发动机”

一边是基于 alien-signals 重构的响应式内核,公开的 refcomputedwatch 用法基本不变;另一边是正式进入 RC 阶段的 Vapor Mode,它让 Vue 单文件组件可以绕过虚拟 DOM,编译为更直接的 DOM 更新逻辑。

不过,先把最重要的版本信息放在前面:

截至 2026 年 7 月 26 日,Vue 3.6 的最新版本是 3.6.0-rc.2。RC 是候选发布版,不是稳定版。本文适合用来评估、试验和准备迁移,不代表所有生产项目都应该立即升级。

先看结论:3.6 改变了什么

对比维度Vue 3.5Vue 3.6 RC对现有项目的实际影响
响应式系统3.5 已做过内部优化基于 alien-signals 大幅重构常规 Composition API 写法通常不需要重写,但应回归复杂副作用与调度逻辑
默认渲染模式Virtual DOM仍然是 Virtual DOM单纯升级依赖不会让应用自动进入 Vapor
Vapor Mode尚未作为 3.5 的正式能力交付功能集进入 RC,100% 显式启用可以从单个性能敏感区域开始试验
应用体积默认包含 VDOM runtime纯 Vapor 应用可不引入 VDOM runtime只有纯 Vapor 或边界清晰的场景,体积收益才容易兑现
API 覆盖完整 Vue 3 API 生态Vapor 支持 Vue API 的一个子集Options API、实例代理相关能力不能直接迁移
VDOM / Vapor 混用不适用通过 vaporInteropPlugin 互操作标准 props、事件、slots 已覆盖,但复杂嵌套仍需测试
事件委托原生监听语义rc.2 起默认直接绑定;.delegate 才显式委托不要沿用 rc.1 的默认委托认知
适合生产吗稳定版当前仍是预发布版生产项目应等待稳定版和上层生态明确支持

一句话概括:

Vue 3.5 的亮点更接近“开发体验和 SSR 能力升级”,Vue 3.6 的核心则是“响应式内核与渲染架构升级”。

从 3.5 到 3.6:变化重心已经不同

Vue 3.5 没有破坏性变化,它带来的能力大多能直接被业务开发感知:

  • 响应式 Props 解构正式稳定;
  • useTemplateRef() 改善模板引用的组织方式;
  • onWatcherCleanup() 让 watcher 清理逻辑更自然;
  • useId() 提供 SSR 友好的稳定 ID;
  • 异步组件支持懒激活(Lazy Hydration);
  • data-allow-mismatch 可以声明允许的 hydration 差异;
  • Deferred Teleport 与自定义元素能力得到增强。

3.6 当然也包含大量修复,但它最值得关注的两件事——alien-signals 与 Vapor——都位于框架的底层。你可能不会在业务代码里多写一个新 API,却会面对新的性能特征、编译产物和运行时边界。

这也决定了升级思路:不要只检查“代码能不能编译”,还要检查响应式行为、SSR hydration、组件互操作和真实性能。

变化一:响应式内核切换到 alien-signals

Vue 3.6 对 @vue/reactivity 做了大规模重构,其基础来自 StackBlitz 开源的 alien-signals。

对于绝大多数业务开发者,下面这些代码仍然是熟悉的 Vue:

import { computed, ref, watchEffect } from 'vue'

const price = ref(99)
const count = ref(2)
const total = computed(() => price.value * count.value)

watchEffect(() => {
  console.log(total.value)
})

变化主要发生在内部:依赖如何建立、状态如何标记、计算属性何时失效、effect 如何沿依赖图传播,以及这些关系如何被清理和复用。

由活跃与休眠路径组成的细粒度响应式依赖网络

这张图表达的是依赖传播的概念,不是 Vue 内部数据结构的逐字段示意。

性能数字应该怎样理解

Vue 核心仓库的 alien-signals 合并 PR 给出过两类微基准结果:

  • 在大量 refcomputed 和 effect 实例的构造场景中,示例内存从约 2.3 MB 降至约 2.0 MB,约减少 13%;
  • 在“一个源变化后,大量 computed 被读取”的特定压力场景中,性能提升可以超过 30 倍。

第二个数字很亮眼,但不能直接翻译成“Vue 3.6 应用快 30 倍”。它证明的是:新的依赖传播算法在某些过去成本会随规模显著上升的图结构中,复杂度表现更好。

真实页面还包含 DOM、布局、网络、组件库、序列化和业务计算。升级前后的判断应基于自己项目的 flame chart、交互延迟、内存曲线和打包结果,而不是套用框架微基准。

哪些项目最可能感受到收益

  • 大量 computed 相互依赖的数据看板;
  • 高频修改、筛选和派生状态很多的编辑器;
  • 长时间运行、创建和销毁大量 effect 的工作台;
  • 表单字段多、验证规则和联动关系复杂的应用;
  • 基于 Vue 响应式原语构建的状态管理或工具库。

普通内容页也能得到内部改进,但用户未必会感知到明显差异。

谁需要格外谨慎

如果代码只使用公开的 refreactivecomputedwatcheffectScope,迁移风险相对可控。真正需要警惕的是:

  • 直接读取或修改 Vue 响应式内部字段;
  • 依赖未公开的 effect、Dep 或 scheduler 实现细节;
  • 自行 monkey patch 响应式函数;
  • 对 watcher 执行顺序、同步刷新和清理时机有隐含假设;
  • 库代码同时支持多个 Vue 次版本,却没有覆盖这些边界测试。

内部重构的意义,正是 Vue 可以在保持公开 API 的同时更换实现。反过来说,依赖内部实现的代码也最容易在这类升级中暴露问题。

变化二:Vapor Mode 不再只是实验概念

Vapor Mode 是 Vue SFC 的一种新编译模式。传统 Vue 模板会生成 VNode,由 Virtual DOM runtime 对比前后两棵树,再把差异更新到真实 DOM;Vapor 则让编译器提前识别动态部分,生成更直接、粒度更细的更新逻辑。

它的目标有两个:

  1. 降低应用的基础包体积;
  2. 减少运行时创建、遍历和比较 VNode 的成本。

官方发布说明称,Vapor 已在第三方 js-framework-benchmark 中达到与 Solid、Svelte 5 相近的级别。这个结论同样应该按“基准场景”理解,而不是把不同框架、不同应用的真实性能压缩成一条排名。

Vapor 不会在升级后自动开启

Vue 3.6 依然默认使用 VDOM。要让一个 SFC 使用 Vapor,需要显式标记:

<script setup vapor lang="ts">
import { ref } from 'vue'

const count = ref(0)
</script>

<template>
  <button @click="count++">
    Count: {{ count }}
  </button>
</template>

官方还支持两个等价入口:

<script vapor>
// <script setup vapor> 的简写
</script>
<template vapor>
  <!-- 整个 SFC 使用 Vapor 编译 -->
</template>

也就是说,团队可以升级到 3.6 后继续运行现有 VDOM 应用,再有选择地迁移某个组件或页面。

纯 Vapor 应用

如果应用完全由 Vapor 组件组成,可以使用:

import { createVaporApp } from 'vue'
import App from './App.vue'

createVaporApp(App).mount('#app')

这种模式不需要引入 Virtual DOM runtime,最容易获得基础包体积收益。它更适合小型新应用、交互小工具,或可以明确约束技术栈的独立页面。

在现有 VDOM 应用中使用 Vapor

现有 createApp() 项目需要安装互操作插件:

import { createApp, vaporInteropPlugin } from 'vue'
import App from './App.vue'

createApp(App)
  .use(vaporInteropPlugin)
  .mount('#app')

反过来,Vapor 应用也能安装这个插件以容纳 VDOM 组件,但这样会重新带入 VDOM runtime,削弱体积优势。

Render Function 与 JSX 编写的组件仍然属于 VDOM 组件。在纯 Vapor 应用中使用它们,同样需要互操作。

现有 VDOM 区域通过明确的互操作边界连接到独立 Vapor 区域

我的建议与官方一致:把两种渲染模式组织成边界清楚的区域,而不是在每一层组件中来回套娃。

例如,把一个高频更新的数据画布做成 Vapor 页面或子树,周围的后台导航、弹窗和成熟组件库继续使用 VDOM。这样的收益、故障范围和回退路径都更容易测量。

rc.2 最容易踩坑的变化:事件委托改为显式启用

如果你在 rc.1 阶段已经试过 Vapor,这一节尤其重要。

rc.1 的说明中,符合条件的事件会自动委托到 document。但这与原生 DOM 和标准 Vue 的行为存在差异:如果祖先元素提前调用 stopPropagation(),事件到不了 document,子元素被委托的 handler 也不会执行。

3.6.0-rc.2 开始,Vapor 默认把 DOM 监听器直接绑定到元素。只有明确希望使用文档级委托时,才添加 Vapor 专用的 .delegate 修饰符:

<button @click.delegate="onClick">
  保存
</button>

同时,旧的 compilerOptions.eventDelegation 已被移除。

迁移时应该做两件事:

  1. 删除已有的 compilerOptions.eventDelegation
  2. 只对数量大、事件稳定,并且传播路径已验证的监听器使用 .delegate

这不是一个适合全局机械替换的优化。事件是否值得委托,要结合节点数量、生命周期和传播语义判断。

Vapor 与标准 Vue 的兼容边界

Vapor 的目标不是在第一天覆盖 Vue 的所有历史能力。官方明确说明,它支持现有 Vue API 的一个子集;依赖 VNode 或组件公开实例代理的功能,目前不能直接使用。

能力VDOM 组件Vapor 组件
Composition API支持主要编程方式
Options API支持不支持
app.config.globalProperties支持不支持
getCurrentInstance()返回当前实例返回 null
Render Function / JSX原生 VDOM仍是 VDOM,混用需要 interop
v-memo支持不适用 / 不支持
@vue:xxx 元素生命周期事件支持不支持
组件模板引用暴露公开实例能力不暴露 $el$props$attrs$slots$refs 等属性
自定义指令标准指令生命周期对象使用 Vapor 专用函数接口

slots.default() 不能再当作无副作用探测

在 VDOM 世界中,一些组件会先调用 slots.default(),检查返回内容,再决定渲染 fallback。Vapor 中调用 slot 可能直接创建 Block 和 DOM、注册响应式 effect,或在 hydration 时认领已有 SSR DOM。

因此不要这样写:

<script setup vapor>
import { useSlots } from 'vue'

const slots = useSlots()
const content = slots.default?.()
const showFallback = !content
</script>

让模板负责 slot 的实际渲染,通常更安全:

<template>
  <slot />
</template>

自定义指令需要单独迁移

Vapor 自定义指令接收节点和响应式 getter,并且可以返回 cleanup 函数。它不是把 VDOM 指令的 mountedupdatedunmounted 对象原样搬过去。

如果项目或组件库依赖大量自定义指令,应该把它们列成独立迁移项,逐个验证响应式更新、清理和 SSR 行为。

Nuxt、Router、Pinia 和组件库应该怎么看

Vue 核心可用,不代表上层框架已经自动完成 Vapor 集成。

Vue 官方的 Vapor Roadmap 单独列出了 Router、Pinia、Nuxt、DevTools 和 Vue Test Utils 等生态工作,其中 Nuxt 还依赖 SSR hydration 能力。对真实项目来说,编译器能否识别 Vapor、服务端产物如何生成、客户端如何 hydration、开发工具怎样检查组件,都是完整链路的一部分。

因此我会把项目分成两类:

普通 Vue / Vite 应用

可以在分支中升级 3.6 RC,先验证现有 VDOM 模式,再挑一个叶子页面试用 Vapor。依赖关系比较直接,问题也更容易归因。

Nuxt、SSR 或重度组件库应用

不要仅通过 package override 强行把底层 Vue 换成 RC,就把它视为完成 Vapor 升级。应该先确认当前框架、构建插件和 SSR 链路明确支持对应版本,再进行 hydration、路由切换、异步组件和组件库互操作测试。

即使暂时不使用 Vapor,测试 Vue 3.6 的新响应式内核仍然有价值;只是这类试验最好留在独立分支或测试环境。

一套更稳妥的升级路线

第一阶段:只升级依赖,不启用 Vapor

普通 Vue / Vite 项目可以在实验分支中安装 RC:

pnpm add vue@3.6.0-rc.2

如果项目直接依赖 @vue/server-renderer,让它与 Vue 保持同一版本:

pnpm add vue@3.6.0-rc.2 @vue/server-renderer@3.6.0-rc.2

然后先验证原有 VDOM 应用:

  • 单元测试与组件测试;
  • 首屏 SSR 与客户端 hydration;
  • watch、computed、effectScope 的复杂场景;
  • 快速路由切换后的副作用清理;
  • 自定义指令、Teleport、Suspense 和异步组件;
  • 开发与生产构建;
  • 浏览器控制台 warning 和错误;
  • 关键交互的耗时与内存基线。

如果这一阶段失败,问题大概率来自新响应式实现或 RC 回归,而不是 Vapor,定位会简单得多。

第二阶段:选择一个边界清楚的区域

合适的试点通常同时满足:

  • 使用 Composition API;
  • 很少依赖组件实例;
  • 不依赖复杂的 VDOM 组件库;
  • 更新频率高,确实存在性能压力;
  • 有独立路由或明确的组件树边界;
  • 有可重复的性能测试。

先记录迁移前的 JavaScript 体积、交互延迟、CPU 时间和内存,再启用 Vapor。没有基线,就很容易把“技术上成功运行”误判成“值得迁移”。

第三阶段:验证互操作与 SSR

至少覆盖这些组合:

  1. VDOM 父组件嵌套 Vapor 子组件;
  2. Vapor 父组件嵌套 VDOM 子组件;
  3. props、emit 与双向绑定;
  4. 默认 slot、具名 slot 与作用域 slot;
  5. Suspense、异步组件与错误边界;
  6. 服务端输出、hydration 和 mismatch 恢复;
  7. 组件卸载后的 watcher、事件与指令 cleanup。

rc.2 的修复列表中有相当多内容正好集中在 hydration、Suspense、slot anchor 和 VDOM interop。这说明这些区域正在快速收敛,也说明它们是当前最值得测试的地方。

第四阶段:等稳定版再决定生产节奏

RC 的意义是功能集已经接近确定,接下来集中发现回归和边缘问题;它不等于生态已经完全稳定。

生产项目至少应该同时满足:

  • Vue 3.6 正式版已发布;
  • 使用的框架和构建工具明确支持;
  • 核心组件库通过互操作验证;
  • DevTools、测试工具和 SSR 链路可用;
  • 性能收益足以覆盖迁移与维护成本;
  • 有随时退回 VDOM 的方案。

不建议做的四件事

1. 不要把 RC 当成普通补丁版

预发布阶段的行为仍可能调整。rc.1 到 rc.2 的事件委托变化,就是最直接的例子。

2. 不要为了“用上 Vapor”迁移全部组件

导航、静态内容、低频设置页未必能获得有意义的收益。优先迁移性能瓶颈,而不是追求迁移比例。

3. 不要把微基准数字当作应用承诺

“超过 30 倍”来自特定响应式压力场景;“与 Solid、Svelte 5 同级”来自第三方基准。它们适合证明技术方向,不适合替代项目测量。

4. 不要忽略生态边界

Vue 核心、SFC 编译器、Vite 插件、Nuxt、SSR、Router、Pinia、组件库、DevTools 和测试工具共同组成开发体验。只让其中一个包进入 RC 版本,不代表整条链路已经升级完毕。

我的项目类型建议

项目类型现在是否值得试建议
小型新工具、内部实验值得可以尝试纯 Vapor,重点测包体积与交互
已有 Vue SPA值得在分支试先保持 VDOM,再迁移单个性能敏感页面
Nuxt / SSR 站点适合研究,生产宜等待先确认框架支持,重点测 hydration
组件库应尽早做兼容测试检查实例代理、slots、自定义指令和 interop
大型数据看板 / 编辑器很值得压测单独比较 alien-signals 与 Vapor 各自带来的收益
内容型官网优先级较低等稳定版和生态成熟,避免为有限收益增加复杂度

最后的判断

Vue 3.6 RC 最有价值的地方,不是提供了多少个可以立刻写进业务的新 API,而是同时推进了两个长期问题:

  • Vue 的响应式系统能否在更复杂的依赖图中保持高效;
  • Vue 的模板能否在保留熟悉开发体验的同时,摆脱必须依赖虚拟 DOM 的成本。

alien-signals 回答第一个问题,Vapor 尝试回答第二个问题。

对于现有项目,我认为最合理的策略是:先把 3.6 当作响应式内核升级来测试,再把 Vapor 当作可选的局部编译模式来评估。 两件事分开验证,才能知道性能变化来自哪里,也能把风险控制在清晰的边界内。

Vue 3.6 还没有到“所有人今天就应该升级”的阶段,但它已经到了“值得所有 Vue 团队开始理解”的阶段。


资料说明

本文中的升级建议是我基于官方资料和工程经验做出的判断,文章由 AI 协助资料整理与语言校对;具体项目仍应以自身测试结果为准。

END OF SIGNAL
READER CHANNEL

留言

00
还没有留言。成为第一个发出回应的人。