2025年2月14日 — Matt Carroll と Ricky Hanlon
Create React App の廃止
本日、Create React App を新規アプリ向けに非推奨(deprecated)とし、既存アプリにはフレームワークへの移行、もしくは Vite、Parcel、RSBuild のようなビルドツールへの移行を推奨します。フレームワークがプロジェクトに合わない場合や、自分でフレームワークを作りたい場合、あるいは React をスクラッチから学びたい場合のためのドキュメントも公開しています。
背景
2016年に Create React App を公開した当時、新しい React アプリを作る明確な方法はありませんでした。JSX、lint、ホットリロードなどの基本機能をサポートするために多くのツールをインストールして自分で組み合わせる必要があり、正しく設定するのは非常に難しかったため、コミュニティは共通セットアップのためのボイラープレートを作成しました。しかし、ボイラープレートは更新が難しく、断片化により React が新機能を出すのが困難になりました。Create React App は複数のツールを単一の推奨設定にまとめることでこれらの問題を解決しました。これにより、アプリは新しいツール機能へ簡単にアップグレードでき、React チームは Fast Refresh サポートや React Hooks の lint ルールなど、非自明なツール変更を広いユーザーに展開できました。このモデルは非常に普及し、今日では同様の仕組みのツールカテゴリが存在します。
Create React App の非推奨について
Create React App は簡単に始められる一方で、高性能なプロダクションアプリを構築するにはいくつかの制約があります。本来であればフレームワークへと進化させることでこれらを解決することもできますが、Create React App には現在アクティブなメンテナが存在せず、これらの課題をすでに解決している多くのフレームワークが存在するため、Create React App を非推奨とする判断をしました。
本日以降、新しいアプリをインストールすると、以下のような非推奨警告が表示されます:
create-react-app is deprecated. You can find a list of up-to-date React frameworks on react.dev
For more info see: react.dev/link/cra
このエラーメッセージはインストールごとに一度だけ表示されます。また、Create React App のウェブサイトと GitHub リポジトリにも非推奨のお知らせを追加しました。Create React App はメンテナンスモードで動作し続け、React 19 と互換する新しいバージョンも公開済みです。
フレームワークへの移行方法
新しい React アプリはフレームワークで作成することを推奨します。推奨するフレームワークはすべてクライアントサイドレンダリング(CSR)とシングルページアプリ(SPA)をサポートし、サーバー無しで CDN や静的ホスティングへデプロイできます。
既存アプリをクライアント専用の SPA に移行する際のガイド例:
- Next.js の Create React App 移行ガイド
- React Router のフレームワーク導入ガイド
- Expo (webpack から) → Expo Router 移行ガイド
ビルドツールへの移行方法
アプリに特殊な制約がある場合や、自分でフレームワークを作って問題を解決したい場合、あるいは React をスクラッチから学びたい場合は、Vite、Parcel、Rsbuild などのビルドツールでカスタムセットアップを作ることができます。
既存アプリをビルドツールへ移行する際のガイド例:
- Vite Create React App migration guide
- Parcel Create React App migration guide
- Rsbuild Create React App migration guide
また、Vite、Parcel、Rsbuild を使って始めるための「Building a React App from Scratch」のドキュメントも追加しました。
深掘り
フレームワークは必要か?
ほとんどのアプリはフレームワークから恩恵を受けますが、スクラッチで React アプリを作るのが正当なケースもあります。経験則として、アプリにルーティングが必要ならフレームワークを利用した方が良いでしょう。Svelte に SvelteKit、Vue に Nuxt、Solid に SolidStart があるように、React でもデータフェッチやコード分割などと密に統合されたルーティングを提供するフレームワークを使うことを推奨します。自分で複雑な設定を書いて事実上フレームワークを作る手間を避けられます。
とはいえ、Vite、Parcel、Rsbuild のようなビルドツールを使ってスクラッチで React アプリを構築することも可能です。以下ではビルドツールの制約と、なぜフレームワークを推奨するかを説明します。
ビルドツールの制約
Create React App や同様のビルドツールは、React アプリを始めるのを簡単にします。npx create-react-app my-app を実行すると、開発サーバー、lint、プロダクションビルド付きのすぐに使える React アプリが手に入ります。たとえば内部管理ツールを作るとき、ランディングページから始められます:
export default function App() {
return (
<div>
<h1>Welcome to the Admin Tool!</h1>
</div>
)
}
これにより JSX、デフォルトの lint ルール、開発・本番両方で動くバンドラーなどですぐにコーディングを始められます。しかし、このセットアップには本番アプリを構築するために必要なツールが欠けています。ほとんどのプロダクションアプリは、ルーティング、データフェッチ、コード分割のような問題への解決策を必要とします。
ルーティング
Create React App には特定のルーティングソリューションが含まれていません。始めたばかりなら useState でルートを切り替える方法もありますが、これではアプリへのリンクを共有できず、すべてのリンクが同じページに行ってしまいます。徐々にアプリ構造が難しくなります:
import { useState } from 'react';
import Home from './Home';
import Dashboard from './Dashboard';
export default function App() {
const [route, setRoute] = useState('home');
return (
<div>
{route === 'home' && <Home />}
{route === 'dashboard' && <Dashboard />}
</div>
)
}
このため、Create React App を使う多くのアプリは React Router や Tanstack Router のようなルーティングライブラリを追加してルーティングを実装します。ルーティングライブラリを使えば、アプリに追加のルートを加え、アプリの構造に対する意見(opinion)を提供し、ルートへのリンクを共有できるようになります。React Router の例:
import { RouterProvider, createBrowserRouter } from 'react-router';
import Home from './Home';
import Dashboard from './Dashboard';
const router = createBrowserRouter([
{ path: '/', element: <Home /> },
{ path: '/dashboard', element: <Dashboard /> }
]);
export default function App() {
return (
<RouterProvider value={router} />
)
}
ルーティングライブラリを導入すると、ネストされたルート、ルートガード、ルート遷移など、ライブラリなしでは実装が難しい機能を追加できます。ルーティングライブラリはアプリに複雑さを加えますが、それと引き換えに得られる機能は多くの場合有益です。
データフェッチ
Create React App には特定のデータフェッチソリューションは含まれていません。始めのうちはコンポーネント内の effect で fetch を使うことが一般的ですが、これだとコンポーネントが描画された後にデータを取りに行くため、ネットワークウォーターフォール(network waterfalls)を引き起こす可能性があります。ネットワークウォーターフォールは、コードのダウンロードと並列でデータを取得するのではなくレンダリング時にデータを取得することで発生します:
export default function Dashboard() {
const [data, setData] = useState(null);
useEffect(() => {
fetch('/api/data')
.then(response => response.json())
.then(data => setData(data));
}, []);
return (
<div>
{data.map(item => <div key={item.id}>{item.name}</div>)}
</div>
)
}
effect 内でフェッチすると、ユーザーがコンテンツを見るまでに余分な待ち時間が発生します。これを解決するには TanStack Query、SWR、Apollo、Relay などのデータフェッチライブラリを使い、プリフェッチやキャッシュを利用してリクエストをコンポーネント描画前に開始する方法があります。これらのライブラリはルーターの「loader」パターンと統合すると最も効果的で、ルートレベルでデータ依存関係を指定でき、ルーターがデータフェッチを最適化できます:
export async function loader() {
const response = await fetch(`/api/data`);
const data = await response.json();
return data;
}
export default function Dashboard({ loaderData }) {
return (
<div>
{loaderData.map(item => <div key={item.id}>{item.name}</div>)}
</div>
)
}
初回ロード時、ルーターはルートがレンダリングされる前にデータを即座にフェッチできます。ユーザーがアプリ内を移動するとき、ルーターはルートとデータの両方を同時に取得して並列化できるため、画面にコンテンツが表示されるまでの時間を短縮できます。ただし、これにはアプリでのローダー設定を正しく行う必要があり、複雑さとパフォーマンスのトレードオフがあります。
コード分割
Create React App は特定のコード分割ソリューションを含んでいません。始めたばかりだとコード分割を全く考慮しないことがあります。その場合、アプリは単一バンドルとして配信されます:
しかし理想的なパフォーマンスのためには、ユーザーが必要とするコードだけをダウンロードするようにコードを分割すべきです。これにより、ユーザーがページを見るまでの待ち時間を減らせます:
- core.js 25 kb
- home.js 25 kb
- dashboard.js 25 kb
コード分割の一つの方法は React.lazy を使うことですが、これだとコンポーネントが描画されるまでコードがフェッチされず、ネットワークウォーターフォールが発生することがあります。より最適な解は、ルーターの機能でコードをダウンロード中に並列でフェッチする方法を使うことです。たとえば React Router はルートに対して lazy オプションを提供し、ルートをコード分割していつロードするかを最適化できます:
import Home from './Home';
import Dashboard from './Dashboard';
const router = createBrowserRouter([
{ path: '/', lazy: () => import('./Home') },
{ path: '/dashboard', lazy: () => import('Dashboard') }
]);
最適化されたコード分割は正しく行うのが難しく、ユーザーが必要以上のコードをダウンロードしてしまうミスを起こしやすいです。ルーターやデータローディングと統合することで、キャッシュの最大化、フェッチの並列化、ユーザー操作時にインポートするパターン(import on interaction)をサポートするのが最も効果的です。
その他
ここで挙げたのは Create React App の制約のいくつかに過ぎません。ルーティング、データフェッチ、コード分割を統合した後は、ペンディング状態、ナビゲーションの中断、ユーザー向けのエラーメッセージ、データの再検証(revalidation)なども考慮する必要があります。ユーザーが解決すべき問題カテゴリは多数あります:
- アクセシビリティ
- アセット読み込み
- 認証
- キャッシュ
- エラー処理
- データの変更(ミューテーション)
- ナビゲーション
- 楽観的更新
- プログレッシブエンハンスメント
- サーバーサイドレンダリング
- 静的サイト生成
- ストリーミング
これらはすべて最適な読み込みシーケンスを作るために連携します。Create React App 上でこれらの問題を個別に解決するのは難しいことが多く、相互に関連しているため専門的な知識を要します。結果として、ユーザーは Create React App の上に独自のソリューションを構築することになりますが、それこそが Create React App が最初に解決しようとした問題でした。
なぜフレームワークを推奨するのか
Create React App、Vite、Parcel のようなビルドツールでこれらのすべてを自分で解決することもできますが、フレームワークはルーティング、データフェッチ、コード分割、キャッシュ戦略、ビルド最適化などを統合的に扱うことで、開発者が再発明する手間を減らし、プロダクション向けに最適化された経験を提供します。
(続き:元記事の意図と詳細ガイドへのリンクを参照してください。)