Vapor Mode 是什么

Vue 3 的渲染器走的是“虚拟 DOM”路线:组件渲染产生 VNode,再由 diff 算法找出最小变更。这套方案通用性强,但要付出创建 VNode、遍历、diff 的运行时开销。

Vapor Mode 是 Vue 的新一代编译策略:在编译阶段分析模板,直接生成“更新某个 DOM 节点属性/文本”的命令式代码,完全跳过虚拟 DOM 与 diff。它借鉴了 Solid 的思路,同时保留了 Vue 的模板语法与单文件组件体验。

开启方式

npm i vue@latest vite@latest @vitejs/plugin-vue@latest
// vite.config.ts
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";

export default defineConfig({
  plugins: [
    vue({
      // 全局启用 Vapor(也可在单个 SFC 上用 <script setup vapor>)
      vapor: true,
    }),
  ],
});

单个组件开启更稳妥,便于渐进迁移:

<script setup vapor>
import { ref } from "vue";

const count = ref(0);
const double = computed(() => count.value * 2);
</script>

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

编译产物大致等价于:

// 伪代码:编译器生成的命令式更新
const btn = document.createElement("button");
let text = document.createTextNode("");
btn.appendChild(text);

effect(() => {
  // 依赖被精确追踪,只更新这一个文本节点
  text.nodeValue = `${count.value} / ${double.value}`;
});

没有 VNode、没有 diff,更新粒度精确到单个绑定。

alien-signals:更快的响应式内核

Vue 3.6 把响应式实现换成了尤雨溪开发的 alien-signals。核心是“版本计数 + 双向链表”的依赖追踪:

import { signal, computed, effect } from "vue";

// 3.6 起 signal 作为一等 API 暴露
const price = signal(10);
const qty = signal(2);
const total = computed(() => price() * qty());

effect(() => {
  console.log("total =", total());
});

qty.set(3); // 只重算 total 与上面的 effect

相比旧的 Dep/effect 用 Set 存依赖,alien-signals:

  • 用版本号代替脏标记批量失效,避免 Set 迭代开销;
  • 链表结构让依赖增删为 O(1);
  • 内存占用更可控。

在官方 benchmark 中,ref 读写与深层响应式对象的传播性能都有数倍提升,对大型表格、实时看板这类“高频更新”场景收益最直接。

与现有代码的关系

<script setup>
import { ref, shallowRef, watch } from "vue";

// 大型列表建议用 shallowRef,避免深层代理开销
const rows = shallowRef([]);

async function load() {
  rows.value = await fetchRows(); // 整体替换,触发一次更新
}

// watch 现在支持更细的 once 选项
watch(rows, () => console.log("rows changed"), { once: true });
</script>

需要注意的边界:

  1. Vapor 与 vDOM 组件可混用,但同一次渲染中跨模式传参会有额外适配开销,建议按路由或页面整体切换。
  2. 依赖模板编译:运行时动态渲染(如 h() 手写渲染函数、动态组件字符串模板)无法享受 Vapor 优化。
  3. SSR 与 Hydration 已支持,但生态库(UI 组件库)需要各自适配,迁移前先确认依赖版本。

性能验证方法

// perf.ts
import { bench } from "vitest";
import { createApp } from "vue";
import App from "./App.vue";

bench("mount 1000 rows", async () => {
  const app = createApp(App);
  const el = document.createElement("div");
  app.mount(el);
});
npx vitest bench --run

用真实业务组件压测,而不是只看微基准,才能反映 diff 消除带来的实际收益。

小结

Vue 3.6 是一次“保留开发者体验、替换底层实现”的教科书式升级:模板照旧写,编译器和响应式内核变得更聪明。建议先在列表页、看板页这类性能敏感页面上试点 <script setup vapor>。