Vue.js 为什么要推出 Vapor Mode?

前言

Vapor ModeVue 3.6 推出的一个新的高效渲染模式,它实现了无虚拟DOM并大幅度提升性能。

先了解下 Vue 各版本的渲染机制:

  • Vue 1.0:直接操作真实 DOM。
  • Vue 3.6 之前:生成虚拟 DOM,更新时通过比对前后虚拟 DOM 的变化,来更新对应的真实 DOM。
  • Vue 3.6: Vapor Mode 模式,。

1、Vapor Mode 是什么?

Vapor Mode 是 Vue.js 3.6 版本的一个可选编译策略,它在模版编译阶段会生成高效的 JavaScript 代码,直接操作真实 DOM 节点,并通过细粒度的响应式效果(reactive effects)来更新它们。

Vapor Mode核心思想就是,在编译阶段就精确的拿到哪些节点时永不变化的静态节点,哪些是动态节点并与哪个数据源相绑定,这样我们就不需要 VNode 和 DOM Diff 的过程了。

2、Vapor Mode 相比于虚拟 DOM 的好处有哪些?

  • 节省虚拟 DOM 的内存开销 :虚拟 DOM 毕竟是用 JS 对象描述 DOM 并存储在内存中,Vapor Mode 可以节省这部分内存。
  • 节省 DOM Diff 的运行开销 :虚拟 DOM 在更新时需要进行 DOM Diff 比对出最小更新变化,而 Vapor Mode 也可以节省这部分比对的运行开销。
  • 更小的包大小 :它去除了虚拟 DOM 的运行时代码 Virtual DOM runtime code,自然就减少了代码体积。
  • 更高的性能:通过在 effects 中直接对真实 DOM 进行细粒度的更新,性能更高。

3、如何使用 Vapor Mode?

3.1 创建一个 vue3 + ts 的项目

bash 复制代码
pnpm create vite vue3-vapor

3.2 手动修改 vue 版本

手动将 package.json 中的 vue 版本改为最新的 3.6.0-alpha.5,然后运行 pnpm i 命令安装。

json 复制代码
{
  "dependencies": {
    "vue": "3.6.0-alpha.5"
  }
}

3.3 改造入口文件 main.ts

跟 Vue2 中组件或者指令的注册方式类似,Vapor Mode 也有两种引入方式。

方式一:通过 createVaporApp 全局引入

直接使用 createVaporApp 代替 createApp 来创建应用,这样在全局的组件都会采用 Vapor Mode 的模式,而且不会引入虚拟 DOM 的运行时代码,整体应用体积会更小。

ts 复制代码
// main.ts
import { createVaporApp } from 'vue'
import './style.css'
import App from './App.vue'

createVaporApp(App as any).use(vaporInteropPlugin).mount('#app')

方式二:通过 vaporInteropPlugin 插件注册

在入口文件 main.ts 中引入 vaporInteropPlugin 插件,然后可以在组件中按需启用 Vapor Mode

ts 复制代码
// main.ts
import { createApp, vaporInteropPlugin } from 'vue'
import './style.css'
import App from './App.vue'

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

然后我们在组件中通过在 script 标签上增加 vapor 属性,就会启用 Vapor Mode,改变这个组件的编译模式,没有加 vapor 属性的组件还是会使用虚拟 DOM。

vue 复制代码
<script setup vapor>
// ...
</script>

4、Vapor Mode 构建产物分析

导入和辅助函数的区别:

  • 虚拟 DOM 模式:会导入如 _createElementVNode_createElementBlock_toDisplayString_normalizeClass 等函数,用于创建和处理 VNode。
  • Vapor Mode 模式:会导入如 _template_renderEffect_setText_setClass_setDynamicProp 等,用于直接 DOM 创建和更新。

更新机制:

  • 虚拟 DOM 模式:在状态变化时,通过 render 函数生成新的虚拟 DOM,然后 patch 真实 DOM。
  • Vapor Mode 模式:通过 _renderEffect 包裹,每个动态部分(如类、属性、文本)独立跟踪依赖。当响应式值变化时,仅执行对应的 setter 函数(如 _setText(node, value)_setClass(node, value)),直接修改 DOM 无需 diff 过程。

下面来比较下两种模式模式编译后代码的区别。

vue 复制代码
<script setup>
import { ref } from 'vue';
const msg = ref('Hello World!');
const classes = ref('p');
const count = ref(0);
</script>

<template>
  <h1 :class="classes" @click="count++">{{ msg }}</h1>
</template>

虚拟 DOM 模式编译后的代码如下(简化版):

js 复制代码
import { toDisplayString as _toDisplayString, normalizeClass as _normalizeClass, openBlock as _openBlock, createElementBlock as _createElementBlock } from "vue";

export function render(_ctx, _cache) {
  return (_openBlock(), _createElementBlock("h1", {
    class: _normalizeClass(_ctx.classes),
    onClick: _cache[0] || (_cache[0] = () => _ctx.count++)
  }, _toDisplayString(_ctx.msg), 11 /* TEXT, CLASS, NEED_PATCH */));
}

会生成 VNode,使用补丁标志(如 11)标记需要更新的部分。

Vapor Mode 模式编译后的代码如下(简化版):

js 复制代码
import { renderEffect as _renderEffect, setText as _setText, setClass as _setClass, template as _template } from "vue/vapor";

const t0 = _template("<h1></h1>");

export function render(_ctx) {
  const n0 = t0();  // 直接创建 <h1> DOM 节点
  n0.addEventListener('click', () => _ctx.count++);  // 直接事件绑定

  _renderEffect(() => _setText(n0, _ctx.msg));  // 响应式文本更新
  _renderEffect(() => _setClass(n0, _ctx.classes));  // 响应式类更新

  return n0;
}

直接使用 document.createElement 创建节点,事件通过 addEventListener 绑定,更新通过 effects 细粒度执行。

5、Vapor Mode 使用建议

  • Vapor Mode 目前还处于 alpha 版本,不建议在生产环境下使用。
  • 在对性能敏感的组件,可以选择性启动 Vapor Mode 模式提升其性能,这是一种渐进式增强的思想。
相关推荐
白菜__1 小时前
去哪儿小程序逆向分析(酒店)
前端·javascript·爬虫·网络协议·小程序·node.js
前端老曹1 小时前
Jspreadsheet CE V5 使用手册(保姆版) 二
开发语言·前端·vue.js·学习
IT_陈寒1 小时前
SpringBoot3.0实战:5个高并发场景下的性能优化技巧,让你的应用快如闪电⚡
前端·人工智能·后端
秋邱1 小时前
AR 定位技术深度解析:从 GPS 到视觉 SLAM 的轻量化实现
开发语言·前端·网络·人工智能·python·html·ar
老华带你飞1 小时前
动物救助|流浪狗救助|基于Springboot+vue的流浪狗救助平台设计与实现(源码+数据库+文档)
java·数据库·vue.js·spring boot·论文·毕设·流浪动物救助平台
云飞云共享云桌面1 小时前
佛山某机械加工设备工厂10个SolidWorks共享一台服务器的软硬件
大数据·运维·服务器·前端·网络·人工智能·性能优化
开发者小天1 小时前
React中使用classnames的案例
前端·react.js·前端框架
简单的话*1 小时前
Logback 日志按月归档并保留 180 天,超期自动清理的配置实践
java·前端·python
困惑阿三1 小时前
深入理解 JavaScript 中的(Promise.race)
开发语言·前端·javascript·ecmascript·reactjs