コンテンツにスキップ

Create React Appからの移行

AstroのReactインテグレーションは、Astroコンポーネント内でReactコンポーネントを活用する機能を提供します(詳しくはAstroでフレームワークコンポーネントを使う)。これにより、Create React App (CRA) のReactアプリ全体をAstroコンポーネント内で再利用することも可能です。

src/pages/index.astro
---
// CRAプロジェクトのルートAppコンポーネントをインポート
import App from '../cra-project/App.jsx';
---
// クライアントディレクティブでアプリを読み込む
<App client:load />

多くのアプリは、Reactインテグレーションを追加するだけでそのまま動作します。まずはこの方法でプロジェクトをすぐに起動し、機能を保ったまま段階的にAstroへ移行していくのがおすすめです。

時間をかけて、構造を.astro.jsxの組み合わせに変更していきましょう。実際には想像より少ない数のReactコンポーネントで済むケースが多いはずです。

ここでは、移行開始に役立つ主要な概念と戦略を紹介します。さらに詳しくはドキュメント全体やDiscordコミュニティをご活用ください。

CRAサイトをAstroで再構築すると、いくつか重要な違いに気づくでしょう。

  • CRAは単一ページアプリケーションで、index.jsをプロジェクトのルートとして使用します。Astroプロジェクトはマルチページサイトで、index.astroがホームページとなります。
  • .astroコンポーネントは、“ページテンプレートを返すようなexport関数”ではなく、コードフェンス(---)でJavaScriptコードを区切り、その下に生成するHTMLを直接記述する構造を取ります。
  • Astroはコンテンツ駆動設計です。CRAが高いクライアント側インタラクティブ性を前提とする場合、ダッシュボードなどはAstroアイランドやクライアントディレクティブを活用して再現する必要があります。

既存のCRAアプリをAstroでそのまま描画し、段階的に変換していく方法を紹介します。

パッケージマネージャでcreate astroコマンドを実行し、“empty”テンプレートを選択して新しいプロジェクトを作成します。

ターミナルウィンドウ
npm create astro@latest

astro addコマンドでReactインテグレーションを導入します。TailwindやMDXが必要なら同時に指定できます。

ターミナルウィンドウ
npx astro add react
npx astro add react tailwind mdx

CRAが追加のNPMパッケージを必要としている場合は、それらを新しいAstroプロジェクトのpackage.jsonに追記し、インストールしてください。多くのReact依存はAstroでも互換性がありますが、すべてが動作するとは限りません。

既存CRAプロジェクトのソースフォルダ(componentshooksstylesなど)を構造を保ったままsrc/cra-project/にコピーし、.js.jsxまたは.tsxへリネームします。設定ファイルはコピーせず、Astro側のastro.config.mjstsconfig.jsonを使用します。public/配下の静的アセットはAstroのpublic/へ移動します。

  • ディレクトリpublic/
    • logo.png
    • favicon.ico
  • ディレクトリsrc/
    • ディレクトリcra-project/
      • App.jsx
    • ディレクトリpages/
      • index.astro
  • astro.config.mjs
  • package.json
  • tsconfig.json

src/pages/index.astroのフロントマターでCRAのルートコンポーネントをインポートし、ページテンプレート部分で<App />を描画します。

src/pages/index.astro
---
import App from '../cra-project/App.jsx';
---
<App client:load />

既存アプリをAstroに組み込んだ後、次はアプリ自体をAstroへ変換していきます。

基本構造にはAstro HTMLテンプレートコンポーネントを使い、インタラクティブな部分には個別のReactコンポーネント(場合によってはそれ自体が小さなアプリになっていることもあります)をインポートして配置します。

移行のアプローチはプロジェクトごとに異なりますが、動作中のアプリを中断せず段階的に進められます。無理のないペースで個別の機能を変換し、時間をかけて徐々にAstroコンポーネントで動かす範囲を広げましょう。

Reactアプリを変換する際には、どのReactコンポーネントをAstroコンポーネントとして書き直すかを決めます。制約は次のとおりです。AstroコンポーネントはReactコンポーネントをインポートできますが、Reactコンポーネントは他のReactコンポーネントのみをインポートしなければなりません

src/pages/static-components.astro
---
import MyReactComponent from '../components/MyReactComponent.jsx';
---
<html>
<body>
<h1>Astroから直接Reactコンポーネントを使おう!</h1>
<MyReactComponent />
</body>
</html>

AstroコンポーネントをReactコンポーネント内でインポートするのではなく、1つのAstroコンポーネントの中にReactコンポーネントをネストすることもできます。

src/pages/nested-components.astro
---
import MyReactSidebar from '../components/MyReactSidebar.jsx';
import MyReactButton from '../components/MyReactButton.jsx';
---
<MyReactSidebar>
<p>ここはテキストとボタンを含むサイドバーです。</p>
<div slot="actions">
<MyReactButton client:idle />
</div>
</MyReactSidebar>

CRAをAstroプロジェクトとして再構築する前に、AstroアイランドAstroコンポーネント について学んでおくと、移行がスムーズになります。

以下に、CRAコンポーネントと対応するAstroコンポーネントの例を示します。

StarCount.jsx
import React, { useState, useEffect } from 'react';
import Header from './Header';
import Footer from './Footer';
const Component = () => {
const [stars, setStars] = useState(0);
const [message, setMessage] = useState('');
useEffect(() => {
const fetchData = async () => {
const res = await fetch('https://api.github.com/repos/withastro/astro');
const json = await res.json();
setStars(json.stargazers_count || 0);
setMessage(json.message);
};
fetchData();
}, []);
return (
<>
<Header />
<p style={{
backgroundColor: `#f4f4f4`,
padding: `1em 1.5em`,
textAlign: `center`,
marginBottom: `1em`
}}>Astro has {stars} 🧑‍🚀</p>
<Footer />
</>
);
};
export default Component;

以下は、CRAの.jsコンポーネントを.astroコンポーネントへ変換する際のポイントです。

  1. 既存のCRAコンポーネント関数が返すJSXを、HTMLテンプレートのベースとして利用します。
  2. {children}classNameなど、Astro構文リファレンスをAstro構文またはHTML標準属性へ置き換えます。
  3. import文を含む必要なJavaScriptはすべてコードフェンス(---)内へ移動します。※条件付きレンダリングに使うJavaScriptはテンプレート内に直接記述できます。
  4. 追加プロパティはAstro.props (EN)で取得します。
  5. インポートしているコンポーネントを.astroへ変換するか検討します。現在のままReactコンポーネントとして残すこともできますが、インタラクティブ性が不要な場合は将来的に.astroへ書き換えると軽量化できます。
  6. useEffect()で行っていたデータ取得は、import文やimport.meta.glob()でローカルファイルを読み込むか、fetch()で外部データを取得する方法へ置き換えます。

Astroは静的HTMLを出力するため、ビルド後のファイルを使ったE2Eテスト(エンドツーエンドテスト)が可能です。既存のE2Eテスト(JestやPlaywrightなど)が、CRAサイトのマークアップを忠実に再現できていれば、そのまま動くケースも多いでしょう。また、React Testing LibraryやJestをインポートしてAstro上でReactコンポーネントのテストを行うことも可能です。 詳細は テストガイド を参照してください。

ファイルインポートを必ず正しい相対パスで記述します。インポートエイリアスを使うか、フルパスを書くかのいずれかです。

.astroを含む一部のファイル型は拡張子を省略できません。拡張子まで明示してインポートしてください。

src/pages/authors/Fred.astro
---
import Card from '../../components/Card.astro';
---
<Card />

{children}をAstroの<slot />に置き換えます。Astroでは{children}を関数プロップとして受け取る必要はなく、子要素は自動的に<slot />へ描画されます。

src/components/MyComponent.astro
---
---
export default function MyComponent(props) {
return (
<div>
{props.children}
</div>
);
}
<div>
<slot />
</div>

複数の子要素を渡すReactコンポーネントは、名前付きスロットを使ってAstroへ移行できます。 詳しくはスロットの使い方を参照してください。

Create React App でのデータ取得はAstroでも似ていますが、いくつか違いがあります。 サイドエフェクトフック(useEffect())によるローカルファイル取得は削除し、代わりにimport.meta.glob()またはgetCollection()/getEntry()を使います。 リモートデータはfetch()を利用します。 これらの処理はフロントマター---内)でtop-level awaitを使って実行します。

src/pages/index.astro
---
import { getCollection } from 'astro:content';
// src/content/blog/以下のエントリを取得
const allBlogPosts = await getCollection('blog');
// src/pages/post/以下の.mdファイルを取得
const allPosts = Object.values(import.meta.glob('../pages/post/*.md', { eager: true }));
// リモートデータを取得
const response = await fetch('https://randomuser.me/api/');
const data = await response.json();
const randomUser = data.results[0];
---

AstroではCSS-in-JSライブラリ(例:styled-components)がそのまま使えない場合があります。必要に応じて他のCSS手法へ置き換えてください。

  • インラインスタイルオブジェクト(style={{ fontWeight: "bold" }})はHTMLのインライン属性(style="font-weight: bold;")へ変換します。
  • または、Astroの<style>タグを使ってスコープ付きCSSを記述します。
src/components/Card.astro
<div style={{backgroundColor: `#f4f4f4`, padding: `1em`}}>{message}</div>
<div style="background-color: #f4f4f4; padding: 1em;">{message}</div>

Tailwindを使う場合はTailwind Viteプラグインをインストールするだけで、既存のTailwindコードを変更せずに利用できます。 詳しくはAstroでのスタイリングを参照してください。

多くのCRAはAstroでそのまま動作しますが、機能やスタイルを完全に再現するには細かい調整が必要になることがあります。 もし解決策が見つからない場合は、Astro Discord で質問してください。

その他のマイグレーションガイド

貢献する コミュニティ スポンサー