Vue.js概要？ #他のvDOMベースFW との違い

# はじめに

[本文はこちら](https://qiita.com/asip2k25/items/bd4bdccd5201d542953c)

# 他の vDOMベースFW との違い

## Virtual DOM (vDOM) とは？

直訳すると、仮想 DOM、となりますが、DOM とは実は直接、  
関係がありません。  

なので、勘違いしてしまいそうな名前ですが、DOM を置き換える
もの では ありません。

端的に表現すると、HTML のサーバーサイド・レンダリング(SSR)
を  クライアントサイドにもってきて、HTML の再構築前後の差分
のみ 抽出し DOM API を用いてDOM に適用するようにした
仕組み、となります。

仮想DOM APIを用いて、仮想DOMツリー(HTML片)を組み立て、
その仮想DOMツリーが更新された場合、更新前後の仮想DOM
ツリーを比較、差分を抽出し、DOM API を用いて、DOM に
差分(変更)を反映します。

仮想DOM は、DOMを補完する技術です。

仮想DOM では、DOM と同じように HTML の構造をツリー構造と
して表現しています。

## DOM の更新タイミング

vDOM ベース・フレームワークの多く？では、 任意のタイミングで
用意された差分抽出・適用の関数を呼び出して、DOM への差分適用を  
行うことはできません。

Vue.jsでも、DOM の更新は  フレームワークにより管理され自動で
バッチ更新されるようになっています、手動で行うことはできません。

vDOM ベース・フレームワークでは、vDOMツリー差分のみの DOM への
適用により、ブラウザでのUIレンダリングが走る頻度を少なくしています。

::: note info
DOMのみの Vue.js 1.x までは、 DOM 処理のまとめて
バッチ適用により、ブラウザでの UI レンダリングの走る
頻度を少なくしていました、vDOMベースとなった
Vue.js 2.x以降は、他のvDOMベースのフレームワークと
同様に差分のみの DOM への適用により、ブラウザでの
UIレンダリングが走る頻度を少なくしています。
:::

Vue.js (や React)では、フレームワークがvDOMツリーの構築
(旧vDOMツリー)→ステートの更新に伴うvDOMの更新(新vDOM
ツリー)→旧vDOMツリーと新vDOMツリーの差分の抽出→DOMへの
反映の処理をライブラリがカプセル化し隠蔽してくれているので、
ユーザーが意識する必要は(基本的には)ありません。

パフォーマンス上etcの理由から、ユーザー(利用開発者)が差分が
DOMに反映されるタイミングを意識しておくor ユーザーが差分が
DOM に反映されるタイミングを(間接的に)コントロールすることも
場合によっては必要になります。

Vue.jsも(Reactも)画面の再描画の(差分がDOMに反映される)
タイミングをユーザーがある程度(間接的に)コントロールできる
ようになっています。

## vDOM ベース・フレームワークが有効なケースとは？

HTMLがリアルタイムで変化し、UIレンダリングの発生頻度が  
問題になるアプリ、で、主にリアルタイムで画面が変化する
ゲームアプリ  etcで、威力を発揮する気がします。
と、以前書きましたが、現在は、ブラウザのDOM→UIレンダリング
まわりの改良により、vDOMを利用することで発生する新旧vDOM
ツリー間の差分計算→DOMへの反映がパフォーマンス上のネックに
なるようになっていて、リアルタイムで画面が変化するゲームアプリ
etcの開発には、vDOMベース・フレームワークは向いていません。

UIをコンポーネントとして分割して開発し、UIレンダリングの性能が
重視されないアプリに向いています。

## Vue.js の vDOM

Vue.jsは、元々、DOMベースのフレームワークであり、vDOMは
採用されていませんでした。

Vue.js については「vDOM に対する対応を行う予定はない」と  
作者であるEvan You 氏が、以前、Issue にて明言し、
「vDOM対応すると、別物になってしまう」とも書かれていました。

:::note info
ので、DOM APIと同じレベルのレイヤーで DOM APIとの
親和性の高いvDOM(API)ライブラリが出てくれば対応が
行われるかもしれません、と書いていました。
:::

軽量な低レベルvDOM(API)実装 snabbdom がリリースされたこと
で状況が変化し、snabbdom の採用により内部的には vDOM を
採用しつつも、利用者は vDOM を意識しなくても利用できる形で
実装されたVue.js2.0 の開発が進められ、リリースされました。 

Vue.js は 2.0.0 以降、2.xでは、snabbdom をフォークして
カスタマイズした vDOM(API)実装を内蔵しています。v3.0.0以降、 
フル・スクラッチで？書き直した vDOM実装を内蔵しているよう
です。

:::note info
vDOMについては、現状の高レベル・レイヤでの(特定の
フレームワークとタイトに結合した)実装ではなく、
より低レベル・レイヤでの実装が出てきて、フレームワーク
内部で共通に利用されるようにでもならない限り、一般化
してはいかないような気がしますと、以前、書いていました。

パフォーマンス上の問題 etcにより、vDOM(API)実装は汎用化
され、フレームワーク内部で共通利用される方向には進みません
でした。
:::

:::note info
Vue.js の DOM → DOM + vDOM へのスイッチ時点では、
DOMのみの実装 より DOM + vDOM 併用の実装のほうが
クライアントサイドにおいて性能面で有利でした。
:::

Vue.js は、DOMベース → DOM+vDOM の移行を行った後、
バージョンアップを経ながら、内部実装を洗練してきています。

vDOMありきで設計されたフレームワークではないことが
他のvDOMベース・フレームワークとの大きな違いです。

https://ja.vuejs.org/guide/extras/rendering-mechanism#rendering-mechanism

## vDOMベース・フレームワークの課題？

vDOMでは、vDOMツリー(HTML(片))の構築をDOMとは
わけて行い、vDOMツリーの更新前後の差分の抽出を行う
ので、差分まわりのアルゴリズム (特に差分をDOMに反映
するタイミングetcを制御するアルゴリズム)が優秀でない
とダメな気がします。

差分まわりのアルゴリズムは改良されてきていますが、JSで
実装されているので、パフォーマンス面では頭打ちになり
つつある感じです。

Rust etcでvDOMまわり(の一部)を実装、WebAssembly
にコンパイル、JSから呼び出す方向に向かう可能性も
あります。

::: note indo
JS と WebAssembly 間のやりとりには、パフォーマンス上
のオーバーヘッドが存在するので、vDOMまわりを WebAssembly
での実装に置き換えたとしても、パフォーマンスが向上するとは
限りません。
:::

パフォーマンス上のネックかつWebAssembly化によりパフォーマンスが
向上する箇所がWebAssembly化されていくのかもしれません。

サーバーサイドでは、vDOMまわり(の一部)を Rust etcで
Node.js、Deno、Bun で利用可能なネイティブモジュールと
して実装し、JSで呼び出す方向も考えられますが、クライアント
サイドとサーバーサイドで異なる実装となるので、この方向に
進むことはないと考えられます、クライアントサイドを棄てるなら
別ですが。

クライアントサイドで、vDOMベース(WebAssembly化も含めて？)
よりDOMベースのほうがパフォーマンス面で有利なら、クライアント
サイドではvDOMを棄ててDOMベースの実装に回帰していく可能性が
高いように思います。

サーバーサイドについても、SvelteやSolidJSはSSRではHTML
テンプレート(JS/TS含む)を(HTML/CSSを生成する)効率的な
文字列付加コードにコンパイルする造りになっているので、
vDOMベースの実装よりvDOMを利用しない実装のほうが
パフォーマンス上、明確に優位で後方互換性の維持が可能なら、
vDOMベースFWの多くはvDOMを棄てる方向に向かう可能性が高い
でしょう。

vDOM自体、ブラウザのUIレンダリングまわりの実装に
パフォーマンス上の問題があったことで産まれた技術
なので、パフォーマンス上の優位性がなくなれば、廃れ、
消えていく、と考えられます。

## vDOM ベース・フレームワークのこれから

vDOMは、ブラウザのUIレンダリングまわりの実装が熟れておらず、
DOM APIを呼び出すと頻繁にUIの再描画が行われることにより
発生していたパフォーマンス上の問題を、UIの再描画と切り離して、
HTML(片)の更新を行い、変更のあったHTML片(HTMLの更新差分)
のみをDOM に反映することにより、UIの再描画の頻度を減らす
ことで回避し、ブラウザでのUIのパフォーマンスを引き上げて
いました。

近年、ブラウザのUIレンダリングまわりの実装の改善により、
DOM(API)呼び出し時のUIの再描画のパフォーマンスが改善されて  
きたため、ネイティブで実装されている DOM ではなく
JavaScript で実装された vDOM を利用する根拠となっていた  
パフォーマンス上の優位性は なくなっています。

Vue.js / React より後発のフレームワークである Svelte /  
SolidJS では、クライアントサイドではvDOMを利用しない
DOMのみの実装で、vDOMを利用したフレームワークよりも
上の性能を実現しています。

::: note info
Svelte / SolidJS は、CSR/SSRの双方に対応し、サーバーサイド
では、HTMLテンプレート(JS/TS含む)を(HTML/CSSを生成する)
効率的な文字列付加コードにコンパイルする造りになっています。
:::

Svelte / SolidJS は、これらをベースとするフルスタックな？
フレームワーク SvelteKit / SolidStart は存在するものの、
周辺のライブラリは整備中であるため、Vue.js / React に
とって代わるかは未知数です。

vDOM ベース・フレームワーク の多くは、近視眼的には、ハイブリッド
な(vDOM がパフォーマンスで有利なケースでは vDOM を利用、DOM が
パフォーマンスで有利なケースでは DOM のみ利用する) or 脱vDOMな
(DOMのみ利用する)アーキテクチャに移行していく、と考えられます。

:::note info
React は、DOMのみの実装 から vDOMとの併用への移行
が行われた Vue.js とは異なり、最初からvDOMベースであり、  
vDOM ありきの vDOM と密結合した構造となっている(はずな)
ので、ハイブリッドな　or 脱vDOMなアーキテクチャに移行する
には、アーキテクチャの再設計が必要 となる(はずな)ので、
難しく移行しない可能性があります、移行するにしても
時間がかかるのではないか、と思われます。

React が ハイブリッドな or 脱vDOMなアーキテクチャに
移行するケースでは、ユーザーにとっての破壊的な変更を伴う
可能性があります。
:::

サーバーサイドでは、クライアント・サイドとは異なり、DOMより
vDOMのほうが軽量であり、パフォーマンス上のネックとなりえる
新旧vDOM間の差分計算やvDOM→DOMへの反映の処理が不要で
あるため、また、(サーバーサイドでは)パフォーマンス上、DOM
よりvDOMのほうが有利であるため、vDOMベースフレームワーク
では、サーバーサイドでコンポーネントの組み立てを行い、
クライアントサイドでは描画のみを行う、
サーバー・コンポーネントを仕組みとして、最近、
導入しています。

::: note info
サーバー・コンポーネント、Vue.js(本体)では、サポート
されていませんが、Vue.jsベースのフレームワークである
Nuxt(v3以降)ではサポートされています。
:::

https://roe.dev/blog/nuxt-server-components

https://github.com/nuxt/nuxt/issues/19772

::: note info
Reactでは、RSC(React Server Component) として
仕様策定され、React本体とReactベースのフレームワーク
でサポートされつつあります(Next.jsではサポート済み、
React Router v7(旧Remix v2)では未サポート)。
:::

クライアントサイドとサーバーサイドは、WEBアプリにおいて、
車の両輪です。

vDOMにパフォーマンス上のネックのないサーバーサイドに逃げる
のではなく、クライアントサイドでの性能向上に取り組んで
いかないと、vDOMベースFWの多くは、今後、消えていく、
かもしれません。

### Vue.js

vDOMを利用しない、(Vue.jsランタイム利用、クライアントサイド
ではDOMベースの)JavaScriptコードを生成する、テンプレート・
コンパイラのSFC(Single File Component)用新モード、
Vapor Mode が、v3.6での実験的機能？としてのリリースに
向けて、開発中です。

::: note info
Vapor Mode は、CSR/SSR の双方に対応し、vDOMを
利用しないコードを生成します。
:::

Vapor Mode では、Vue.jsランタイムの利用範囲が縮小され、  
より少ないメモリを使用する、パフォーマンス重視のJavaScript
コードが出力されます。

Vapor Component (Vapor Mode利用)と
Vapor-less Component(Vapor Mode非利用)は  
混在可能となる予定です。

::: note info
Vapor Mode は、&lt;script setup&gt; + Composition API で  
記述されたコンポーネント(SFC)のみ、サポートします。
:::

https://qiita.com/ubugeeei/items/73a2416fd46cfe6311a8

https://qiita.com/ubugeeei/items/b28a04a41348b6e49293

vDOM を利用している(内部の)コードも、ブラウザの
UIレンダリングまわりetcの実装の改善に伴い、今後も
改善されていくことが予想されます。

Vue.js は、パフォーマンスでの優位性から、DOM のみ利用から  
vDOM との併用にシフトしているので、vDOMの利点がなくなれ
ば、vDOM との併用から vDOMを利用しない実装(クライアント
サイドではDOM利用)にシフトしていくと思われます。

::: note info
Vapor Mode は、短期的には、オプショナルな機能として
リリースされます。数年？掛けて完成度を高めながら、
中〜長期的には&lt;script setup&gt;のSFCでは現行の
vDOMベースの実装を置き換えていく方向に向かう、
と考えられます。

Vapor Modeは 旧来のOptions API & &lt;script setup&gt;の
SFC以外のコンポーネントをサポートしないため、
Vapor Modeが主流になったとしても、現行のvDOMベース
の実装はOptions API & &lt;script setup&gt;の
SFC以外のコンポーネントのサポートのために(当分は)
残り続けるはずです。
:::

::: note info
Vue.jsでは、vDOM と DOM の違いは、内部で吸収されて
いる、ので、ユーザーが意識する必要はありません。 
:::

## vDOMベースフレームワークの欠点

コンポーネントの再利用に問題があります。

同一フレームワーク内で再利用する場合は問題ないのですが、  
異なるフレームワーク間でコンポーネントを再利用しようと
すると、色々と問題があります。

vDOMベースのフレームワークの場合、vDOM(API)実装を含む
ランタイム　まわり一式をコンポーネントと共にロードする
必要があります。

vDOMベースの別フレームワークを併用する場合、含まれている
vDOM(API)実装は、共通の部品ではなく、それぞれの固有の
実装となっているので、 vDOMベースのフレームワークから
vDOMベースの別フレームワークのコンポーネントを再利用
しようとすると、vDOM(API)実装を含むランタイム全体が
ダブります。

異なるフレームワーク間で再利用できるコンポーネントの開発を　
行う場合、vDOMベースのフレームワークは採用対象外となり、
Svelte etc の DOMベースフレームワークが 採用されること
が多いです。

UIコンポーネント・ライブラリでは、Vue.js / React 用 が　
それぞれ開発されていたり、どちらかにしか対応していなかったり
します。

Vue.js 用 と React 用 のどちらも提供されている場合、
DOMベースフレームワークで開発したコンポーネントをラッピングして　
Vue.js / React 用 のコンポーネントにしていたり します。

vDOMベースのフレームワークの存在は、コンポーネントの自由な
再利用の観点では障害にしか なっていません。

推敲中...