Skip to content

Vue Vapor Mode 安定版

Vue Vapor Mode が Vue 3.6 で正式に安定版となりました。これは Vue 史上最大のランタイムアーキテクチャの変革です——仮想 DOM を完全にバイパスし、ネイティブ DOM 操作に直接コンパイルすることで、手書き JavaScript に近いパフォーマンスを実現します。パフォーマンスが重要なシナリオにおいて、Vapor Mode はまさにゲームチェンジャーです。

Vapor Mode とは ​

従来の Vue コンポーネントはレンダー関数にコンパイルされ、ランタイムが仮想 DOM の差分比較を通じて実際の DOM を更新します。Vapor Mode は仮想 DOM レイヤーを完全にスキップし、コンパイラが直接 DOM API 呼び出しを生成します。

vue
<!-- ソース:通常の Vue コンポーネント -->
<script setup>
import { ref } from "vue";

const count = ref(0);
const increment = () => count.value++;
</script>

<template>
  <div class="counter">
    <p>カウント: {{ count }}</p>
    <button @click="increment">+1</button>
  </div>
</template>

<!-- コンパイル結果(Vapor Mode) -->
<script>
import {
  ref,
  renderEffect as _renderEffect,
  template as _template,
} from "vue/vapor";

const _tmpl = _template(
  '<div class="counter"><p>カウント: <!--t--></p><button>+1</button></div>',
);

export default {
  setup() {
    const count = ref(0);
    const increment = () => count.value++;

    const __returned__ = { count, increment };
    const n0 = _tmpl();
    const n1 = n0.firstChild;
    const t0 = n1.firstChild.nextSibling; // テキストノードのプレースホルダー

    // 直接バインド:仮想 DOM の差分比較なし
    _renderEffect(() => {
      t0.textContent = `カウント: ${count.value}`;
    });

    n0.lastChild.addEventListener("click", increment);
    return __returned__;
  },
};
</script>

重要な違い:_renderEffect が直接 textContent を操作し、vnode の作成も差分比較もパッチもありません。メモリ使用量と CPU 消費の両方が大幅に削減されます。

パフォーマンスベンチマーク ​

ベンチマークでは、Vapor Mode と標準モードのパフォーマンス差異が非常に顕著です:

javascript
// テストシナリオ:1000 行テーブルのソートとフィルタリング
// デバイス:MacBook Air M3、Chrome 131

// 標準モード(仮想 DOM)
// 初回レンダリング:  48ms
// ソート更新:        12ms(1000 ノードの差分比較 + パッチ)
// メモリ使用量:      28MB(vnode ツリー)
// GC 停止時間:       3-5ms

// Vapor Mode(ネイティブ DOM にコンパイル)
// 初回レンダリング:  31ms(-35%)
// ソート更新:        3ms(-75%、直接 DOM 操作)
// メモリ使用量:      11MB(-61%、vnode ツリーなし)
// GC 停止時間:       <1ms

// 極端なケース:10000 行リストのスクロール
// 標準モード:42fps(明らかなフレームドロップあり)
// Vapor Mode:59fps(ネイティブに近い)

メモリが 61% 削減されたことが最も顕著な改善です。仮想 DOM ツリー自体がかなりのメモリオーバーヘッドを持っており、Vapor Mode はそれを完全に排除します。

段階的な移行:Vapor SFC ​

Vapor Mode はコンポーネント単位で有効化できます。パフォーマンスが重要なコンポーネントのみ Vapor を有効にし、他のコンポーネントは標準モードのままにできます:

vue
<!-- vapor 属性で有効化 -->
<script setup vapor>
import { ref, computed } from 'vue';

// このコンポーネントは Vapor モードでコンパイルされる
const props = defineProps<{ items: Item[] }>();
const sorted = computed(() =>
  [...props.items].sort((a, b) => b.score - a.score)
);
</script>

<template>
  <ul>
    <li v-for="item in sorted" :key="item.id">
      {{ item.name }} - {{ item.score }}
    </li>
  </ul>
</template>
javascript
// vite.config.ts - Vapor Mode の設定
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";

export default defineConfig({
  plugins: [
    vue({
      vapor: {
        // グローバルで有効化(すべての SFC をデフォルトで Vapor に)
        enable: true,
        // またはディレクトリ単位で有効化
        include: ["src/components/heavy/**/*.{vue,tsx}"],
        exclude: ["src/components/legacy/**"],
      },
    }),
  ],
});

混合モードでは、Vapor コンポーネントと標準 Vue コンポーネントをシームレスにネストできます。親が Vapor で子が標準モード、またはその逆でも正常に動作します。

Vapor Mode の制限 ​

Vapor Mode は強力ですが、現在いくつかの制限があります:

vue
<!-- ❌ Vapor Mode でサポートされていない機能 -->
<script setup vapor>
import { ref } from "vue";

// ❌ 動的コンポーネント:コンパイル時にコンポーネントが確定している必要あり
// const comp = ref(AComponent);
// <component :is="comp" />

// ❌ Teleport / Transition コンポーネント
// <Teleport to="body">...</Teleport>

// ❌ レンダー関数コンポーネント
// const MyComp = { render() { return h('div') } }
</script>

<!-- ✅ Vapor Mode が完全にサポートする機能 -->
<template>
  <!-- 条件付きレンダリング -->
  <div v-if="show">コンテンツ</div>

  <!-- リストレンダリング -->
  <ul>
    <li v-for="item in items" :key="item.id">{{ item.name }}</li>
  </ul>

  <!-- イベントバインディング -->
  <button @click="handleClick">クリック</button>

  <!-- 双方向バインディング -->
  <input v-model="text" />

  <!-- スロット -->
  <slot name="header" />
  <slot :data="data" />
</template>

コンポーネントが Teleport や動的コンポーネントを使用している場合は、Vapor を有効にしないでください。Vue チームは 3.7 でこれらの機能を補完する予定です。

実プロジェクトへの移行推奨事項 ​

javascript
// 移行戦略:まずベンチマークを実行し、段階的に有効化
// 1. Vue DevTools でパフォーマンスボトルネックのコンポーネントを特定
// 2. データ集約型コンポーネントで Vapor を有効化
// 3. 統合テストを実行して機能が正常であることを確認
// 4. 前後のパフォーマンスデータを比較

// Vapor を有効にするのに適したコンポーネントタイプ:
// ✅ 大規模なリスト/テーブル
// ✅ 高頻度更新のチャートコンポーネント
// ✅ リアルタイムデータ表示パネル
// ✅ アニメーションが多いコンポーネント

// まだ有効にしないほうがよいもの:
// ❌ Teleport を使用するモーダルコンポーネント
// ❌ レンダー関数に依存するサードパーティライブラリコンポーネント
// ❌ keep-alive を使用するページレベルのコンポーネント

まとめ ​

MIT Licensed