2026年10月8日にTypeScript HandbookとMDN Web Performance本文を再確認した。フレームワーク比較は人気や機能一覧ではなく、レンダリング方式、状態・データ取得、アクセシビリティ、型、ビルド、実行環境、更新頻度、チームの習熟、観測・復旧で評価する。フレームワークの選択は性能やSEOの保証ではなく、同じ要件と計測条件で実装・運用を比較し、依存の変更と撤退コストを記録する意思決定である。
JavaScriptの選定では、名前の新しさより「何をどこで動かすか」を先に決めると比較しやすくなります。公開記事を配る画面と、ログイン後に表を編集する画面では、初期表示、データの更新、権限、配信環境に求めるものが違います。
この記事はReact・Vue・Angular・Svelte・Next.js・Nuxtの役割、長所と制約、小さなコード例を比較します。2026年10月4日に確認した公式説明を使い、人気順位や一律の速度ランキングには置き換えません。開発工程全体はモダンWeb開発の進め方、サイト全体の計画はWeb制作の全体像を参照してください。
30秒で要点
- ReactやVueなどのUIを作る仕組みと、Next.jsやNuxtのようにルーティング・描画・配信をまとめる仕組みは、同じ比較階層ではありません。
- CSR・SSR・静的生成は別の選択軸です。フレームワーク名だけで描画方式や必要サーバーは決まりません。
- 学習時間、必要なライブラリ、更新担当、配信環境を含めて比べます。大企業向け・小規模向けと固定しません。
- 候補を絞ったら、同じ画面・操作・データ量で試作し、読み込みと操作、アクセシビリティ、変更のしやすさを確認します。
1. UIの仕組みとアプリ全体の仕組みを分ける
まず、6つの役割を並べます。「標準で何があるか」と「周辺の構成として追加するか」を分ける表です。
表が収まらない場合は、横にスクロールできます
| 選択肢 | 中心となる役割 | 併せて決めること |
|---|---|---|
| React | コンポーネントでUIを表現するライブラリ | アプリ用フレームワーク、またはrouting・データ取得等の構成 |
| Vue | 宣言的な表示とリアクティブな状態を扱うフレームワーク | 必要に応じVue Router、Pinia、SSRを支える構成 |
| Angular | コンポーネントを中心にアプリを組み立てるフレームワーク | route・フォーム・状態・依存の設計、描画方式 |
| Svelte | コンポーネントをコンパイルしてUIを作るフレームワーク | アプリ全体にはSvelteKit等、配信先に合う構成 |
| Next.js | Reactを使うアプリのrouting・server/client境界等 | App Routerの設計、cache、サーバー機能と静的出力の選択 |
| Nuxt | Vueを使うアプリのrouting・描画・server機能等 | universal/CSR/hybrid、server endpoint、配信preset等 |
React公式は新しいアプリにフレームワークから始める方法を案内しています。独自構成も選べますが、routingやデータ取得などを自分たちで選び、統合して保守します。これは「すべてのサイトへReactが必要」という意味ではありません。少量の動きだけなら、HTML・CSSと小さなJavaScriptで要件を満たす案も比較します。
2. CSR・SSR・静的生成をページごとに選ぶ
表が収まらない場合は、横にスクロールできます
| 描画方式 | HTMLを主に用意する時点 | 適用を考える条件 | 確認すべき制約 |
|---|---|---|---|
| CSR | ブラウザでJavaScriptを実行するとき | 操作が多い管理画面など | 初期コード量、遅い端末、JavaScript失敗時の表示 |
| SSR | リクエストに応じてサーバーで描画するとき | 要求時点の情報が必要なページなど | server実行費、データ取得時間、個別情報のcache分離 |
| 静的生成 | buildなど事前に生成するとき | 多くの人へ同じ内容を配れるページなど | 更新反映、生成対象、build時間、動的機能の別構成 |
SSRや静的生成でHTMLを送っても、操作のためのJavaScriptが不要になるとは限りません。ブラウザ側でイベント処理などを結び付けるhydrationが必要な構成があります。サーバーで生成した画面とクライアント側の初期状態をそろえ、windowなどブラウザ専用APIを実行する場所も確認します。
特に、React Server Componentsと「毎回SSRする」は同じ意味ではありません。Next.jsではサーバー側の処理をbuild時に行う構成もあります。静的出力に切り替えるなら、リクエスト依存の機能をそのまま持ち込めるかを別に確認します。
3. React:UIと周辺構成をどう分担するか
Reactは状態からUIを表現するコンポーネントを組み合わせます。既存のReact資産やチームの経験を使える場面では有力な候補です。一方、自由に選べる周辺構成は、選定・更新・障害調査の責任にもなります。
次はReactとJSX変換環境があるプロジェクトのsrc/Counter.jsxです。アプリの入口からこのコンポーネントを表示する前提であり、この1ファイルがプロジェクト全体ではありません。
import { useState } from 'react';
export default function Counter() {
const [count, setCount] = useState(0);
return (
<button type="button" onClick={() => setCount(n => n + 1)}>
回数: {count}
</button>
);
}
状態の更新には前の値を受け取る関数を使っています。実務の試作ではカウンターだけでなく、入力エラー、通信待機、戻る操作を含む画面まで作り、採用したroutingやデータ取得の仕組みと合わせて点検します。
「仮想DOMがあるから常に高速」とは判断しません。不要な再描画、大量データ、送るJavaScript、外部スクリプトなどが結果を変えます。既存のReactアプリへ機能を追加するのか、新規の公開サイトを作るのかでも必要な構成は異なります。
4. Vue:段階導入とSFCの見通しを確かめる
Vueの公式ガイドは、既存HTMLへの段階導入からSPAなどのアプリまで複数の使い方を説明しています。SFC(単一ファイルコンポーネント)では、表示・処理・スタイルを関連付けて扱えます。Options APIとComposition APIの両方があり、既存コードの方式も判断材料です。VueのSFCを扱える環境に置くsrc/Counter.vueの例です。
<script setup>
import { ref } from 'vue';
const count = ref(0);
</script>
<template>
<button type="button" @click="count++">回数: {{ count }}</button>
</template>
小さな状態をコンポーネント内で管理し、複数画面で共有が必要になった段階で設計を広げます。Vue RouterやPiniaを含む状態管理は、Vue本体へすべて内蔵された機能と考えず、目的に応じて採用します。
既存ページへ段階的に追加したい場合や、SFCの構成がチームに合う場合に比較しやすい候補です。ただし、テンプレートが読みやすいと感じることと、大規模な状態や権限を正しく設計できることは別です。SSRではリクエスト間で個人の状態を共有しない構成も必要になります。
5. Angular:共通の構成と更新運用まで試す
AngularではTypeScriptのクラス、テンプレート、メタデータなどを使ってコンポーネントを定義します。共通の設計規約を決めて継続開発するチームでは、構成をそろえる利点があります。その規約、依存関係、更新手順を学ぶ時間も見積もります。
次はstandaloneコンポーネントを扱えるAngular環境で使うcounter.tsです。アプリ側からimportして表示します。signalを読み出すときは関数として呼び、更新時にupdateを使います。
import { Component, signal } from '@angular/core';
@Component({
selector: 'app-counter',
standalone: true,
template: '<button type="button" (click)="increment()">回数: {{ count() }}</button>'
})
export class Counter {
readonly count = signal(0);
increment() {
this.count.update(n => n + 1);
}
}
業務画面ではフォーム、入力検証、データの取得、画面間の状態、依存の注入なども試作の範囲に入れます。既存でRxJSを使っているなら、非同期処理の理解と保守も確認します。企業の規模だけで採用を決めたり、機能が多いだけで必ず重いと決めたりしないことが大切です。
またAngularにもCSR・SSR・prerenderの選択があります。「Angularだからブラウザ描画だけ」とは限りません。サーバーで実行する場合のAPI制約やコストも設計対象です。
6. Svelte:コンパイルとアプリ基盤の境界を見る
SvelteはHTML・CSS・JavaScriptで書く宣言的コンポーネントをコンパイラで変換します。記述方法がチームに合うか、小さなUIから確認できます。コンパイル方式だけから、他の候補より必ず速い・小さいとは言えません。次はSvelteのrunesを扱える環境のsrc/Counter.svelteです。現行公式の$stateの説明に沿い、状態とクリック処理を示しています。
<script>
let count = $state(0);
</script>
<button type="button" onclick={() => count += 1}>回数: {count}</button>
旧構文の既存資産を引き継ぐ場合は、そのコードのモードと移行範囲を確認します。新しい例の構文を、すべての過去プロジェクトへ無条件に貼れるとは限りません。
アプリ全体のroutingや描画にはSvelteKitが候補になります。ページオプションではSSR・hydration・prerenderなどを制御します。必要なUI部品、データ取得、認証連携、配信先のadapter、障害時の情報を確認し、必要な機能がそろうかを試します。
7. Next.js:Reactのserver/client境界を小さく保つ
Next.jsはReactを使ったアプリの構成を提供します。App Routerの公式説明では、pageやlayoutはServer Componentsが基本で、state・イベント・ブラウザAPIが必要な部分へClient Componentsを使います。
Next.jsのApp Routerプロジェクトで、既存のroot layoutがある前提の2ファイルです。app/Counter.jsxに操作を置きます。
'use client';
import { useState } from 'react';
export default function Counter() {
const [count, setCount] = useState(0);
return <button type="button" onClick={() => setCount(n => n + 1)}>回数: {count}</button>;
}
app/page.jsxから使います。1ファイルに2つのdefault exportを置きません。
import Counter from './Counter.jsx';
export default function Page() {
return <main><h1>操作の確認</h1><Counter /></main>;
}
'use client'は「初期HTMLがなく、ブラウザだけで表示する」という意味ではありません。初回表示のHTMLと、操作可能にするhydrationを分けて理解します。また、サーバーで持つ秘密情報をクライアントへ渡すpropsや出力へ混ぜない設計が必要です。
APIの役割も確認するなら、app/api/status/route.jsに次の読み取り専用例を置けます。静的exportの公式例と同じく、要求ごとの情報を使わないJSONを生成する条件を明示します。
export const dynamic = 'force-static';
export function GET() {
return Response.json({ status: 'example', writable: false });
}
これはサーバーの生存監視ではありません。事前生成できる固定内容です。ログイン状態や注文処理などの要求依存の機能が必要なら、静的ファイル配信だけで完結すると判断しないでください。静的exportではcookieやServer Actions、ISRなどに制限があります。
8. Nuxt:Vueの描画と配信方法をまとめて選ぶ
NuxtはVueのアプリを構成し、routingやserver機能などをまとめて扱います。描画方式の公式説明では、universal rendering、CSR、routeごとのhybrid renderingを区別しています。
Nuxt 4系の基本プロジェクトで、app/app.vueを次の内容にした最小画面です。明示的にVueのrefをimportして、状態の出所を示します。
<script setup>
import { ref } from 'vue';
const count = ref(0);
</script>
<template>
<main>
<h1>操作の確認</h1>
<button type="button" @click="count++">回数: {{ count }}</button>
</main>
</template>
universal renderingでは初期HTMLとブラウザでのhydrationの両方を考えます。個別ユーザーの情報をサーバー側の共有状態や共有cacheへ混ぜないこと、サーバーで動かないライブラリを分けることも必要です。
静的に生成して配る構成と、server endpointを実行する構成は同じではありません。公式説明ではnuxt generate等でprerenderだけを出力した場合、server endpointはその出力に含まれません。ホストの名前だけで決めず、使うpresetと機能、更新方法を対応させます。
9. 学習・規模・保守を同じ条件で比較する
「初心者は必ずVue」「大規模なら必ずAngular」「最高速ならSvelte」のような固定表より、次の条件表を埋める方が、選定後の違いを説明できます。
表が収まらない場合は、横にスクロールできます
| 観点 | 比較する具体的な作業 | 記録するもの |
|---|---|---|
| 学習 | 既存画面を読み、1項目と入力エラーを追加 | 調査時間、迷った箇所、レビュー負荷 |
| 機能 | routing、フォーム、表、国際化など必要機能を実装 | 自作部分、外部依存、未充足要件 |
| 状態と規模 | 複数画面・並行編集・大量データを試す | 状態の所有者、分割方法、描画と通信の負荷 |
| 配信 | 対象routeをCSR/SSR/静的生成へ割り当てる | runtime、cache、更新反映、障害時の復旧 |
| 保守 | 依存の更新と1つの不具合修正を試す | 対応版、移行手順、lockfile、担当者 |
| 利用者 | キーボード操作、低速回線、遅い端末で主要経路を確認 | 失敗時の表示、フォーカス、操作と表示の待ち時間 |
ライブラリの多さは、必要なものが保守され、自分たちの条件に合うかと合わせて評価します。採用事例の企業名やダウンロード数だけでは、チームの学習負担や長期の更新作業は分かりません。
性能比較は同じ課題を実装して行う
同じデータ量、同じ画像、同じ操作、同じ端末・回線・cache条件で測ります。初期JavaScriptの量だけでなく、検索・入力・画面遷移中の応答、サーバーのデータ取得、失敗時の挙動を含めます。詳しい測定の切り分けはWeb性能改善の実践で扱います。
このページの短い例では、ソースと記事の変換後コードを照合し、コンパイル・サーバー側の初期出力・状態更新などをローカルで確認します。実ブラウザのクリック、hydration、画面表示、公開先の挙動まで確認済みという意味ではありません。コード例だけから性能比較の結論は出せません。
10. 選定を終える前の確認
候補を2つ程度へ絞ったら、公開ページ1つと操作の多い画面1つを、必要なら別々に試作します。認証が必要な場合は認証と認可の設計、入力の境界はTypeScriptと実行時検証も確認します。
最終的な記録には「採用理由」だけでなく「今回は使わない機能」「別途運用するもの」「再検討する条件」を残します。例えば静的配信を選び、注文APIを別に運用するなら、その責任者と障害の切り分けを明記します。
選定の完了は人気のある名前を決めた時点ではなく、必要な画面を変更・検証・公開後に保守する方法を、チームで説明できる時点です。