Vue 3.6 RC:把 Vapor Mode 搬上生产前,先避开这 6 个坑
vuejs/core 的 v3.6.0-rc.1 release note(2026-07-18)明确了 Vapor Mode 完整功能集,以及 @vue/reactivity 的重大重构。这版核心两件事:响应式系统切到 alien-signals,Vapor Mode 作为新的 SFC 编译模式落地。下面梳理迁移/上生产容易踩坑的点。
Vapor Mode 是什么
Vapor Mode 是一种新的 SFC 编译模式:编译期直接产出命令式代码,不依赖 Virtual DOM,目标是压低基线包体和运行时开销。它 100% opt-in,只支持现有 Vue API 的子集(行为大体一致)。依赖 VNode 或组件公共实例代理的特性在 Vapor 组件里不可用。第三方基准测试显示性能与 Solid、Svelte 5 持平。
开启方式
只支持模板型 SFC 和 ,不支持 Options API。在 上加 vapor 标记:
// ...
也可以打在模板上,让整个 SFC 走 Vapor 编译:
两种建 App 方式
纯 Vapor 应用用 createVaporApp,完全不拉进 Virtual DOM runtime,基线包体最小:
import { createVaporApp } from 'vue'
import App from './App.vue'
createVaporApp(App).mount('#app')
要在普通 VDOM 应用(createApp)里用 Vapor 组件,必须装 vaporInteropPlugin:
import { createApp, vaporInteropPlugin } from 'vue'
createApp(App).use(vaporInteropPlugin).mount('#app')
装了 interop 插件后,Vapor 与 VDOM 组件可以互相嵌套,但只覆盖常规 props/events/slots,边界用例仍有坑——尤其 VDOM 组件库放进 Vapor 模式时。官方建议:应用里尽量按“区域”划分,一种渲染模式一片,少做混合嵌套。
六个迁移坑点
- Options API、
app.config.globalProperties不支持;Vapor 组件里getCurrentInstance()返回null。 v-memo不支持。- 组件模板 ref 不再暴露
$el/$props/$attrs/$slots/$refs这些属性。 - 事件委托 +
stopPropagation:Vapor 把合格事件委托到document,每个元素存自己的 handler,单个document监听器沿事件路径调用。如果某个祖先调了stopPropagation(),事件到不了document,委托 handler 不会执行。下面这些写法会绕过委托、把监听器直接绑到元素上:
slots.default()不是无副作用的“干跑” API:调用它会真正执行 slot 渲染逻辑,可能创建 Blocks/DOM、注册响应式 effect、在 hydration 时认领 SSR DOM。别用它先探空再决定渲染,直接交给模板:
- 自定义指令接口完全不同:
type VaporDirective = (
node: Element | VaporComponentInstance,
value?: () => any,
argument?: string,
modifiers?: DirectiveModifiers,
) => (() => void) | void
value 是响应式 getter,可在 watchEffect 里用它建立响应副作用(组件卸载自动释放),并返回清理函数。
底层:响应式重构到 alien-signals
@vue/reactivity 基于 alien-signals 重构,响应式系统性能和内存占用都有改善。alien-signals 对运行时做了约束(比如避免使用 Array/Set/Map、限制递归)来保证性能。
什么阶段上 Vapor
官方建议目前只用在这两类场景:
- 存量应用局部使用,比如把某个性能敏感页面切成 Vapor;
- 纯新的小应用整站用 Vapor。
整体跑复杂组件库、重度依赖 Options API 或模板 ref 内部属性的老项目,别急着整站切 Vapor,先用 interop 在单页验证。