Create React Appからの移行
AstroのReactインテグレーションは、Astroコンポーネント内でReactコンポーネントを活用する機能を提供します(詳しくはAstroでフレームワークコンポーネントを使う)。これにより、Create React App (CRA) のReactアプリ全体をAstroコンポーネント内で再利用することも可能です。
---// CRAプロジェクトのルートAppコンポーネントをインポートimport App from '../cra-project/App.jsx';---// クライアントディレクティブでアプリを読み込む<App client:load />
多くのアプリは、Reactインテグレーションを追加するだけでそのまま動作します。まずはこの方法でプロジェクトをすぐに起動し、機能を保ったまま段階的にAstroへ移行していくのがおすすめです。
時間をかけて、構造を.astro
と.jsx
の組み合わせに変更していきましょう。実際には想像より少ない数のReactコンポーネントで済むケースが多いはずです。
ここでは、移行開始に役立つ主要な概念と戦略を紹介します。さらに詳しくはドキュメント全体やDiscordコミュニティをご活用ください。
CRAとAstroの類似点
セクションタイトル: CRAとAstroの類似点.astro
ファイルの構文はJSXとよく似ています。Astroを使うのも直感的に感じられるはずです。- Astroはファイルベースのルーティングを採用し、動的ルートもファイル名で定義できます。
- Astroはコンポーネントベースです。マークアップ構造自体は移行前後で大きく変わりません。
- React・Preact・Solid用の公式インテグレーションがあり、既存のJSXコンポーネントをそのまま利用できます。ただし、これらのファイルはAstro内では
.jsx
または.tsx
拡張子を持つ必要があります。 - AstroはNPMパッケージのインストールをサポートしており、Reactライブラリも含まれます。多くの既存依存関係はAstroでも動作することが多いでしょう。
CRAとAstroの主な相違点
セクションタイトル: CRAとAstroの主な相違点CRAサイトをAstroで再構築すると、いくつか重要な違いに気づくでしょう。
- CRAは単一ページアプリケーションで、
index.js
をプロジェクトのルートとして使用します。Astroプロジェクトはマルチページサイトで、index.astro
がホームページとなります。 .astro
コンポーネントは、“ページテンプレートを返すようなexport関数”ではなく、コードフェンス(---
)でJavaScriptコードを区切り、その下に生成するHTMLを直接記述する構造を取ります。- Astroはコンテンツ駆動設計です。CRAが高いクライアント側インタラクティブ性を前提とする場合、ダッシュボードなどはAstroアイランドやクライアントディレクティブを活用して再現する必要があります。
CRAをAstroに組み込む
セクションタイトル: CRAをAstroに組み込む既存のCRAアプリをAstroでそのまま描画し、段階的に変換していく方法を紹介します。
新しいAstroプロジェクトを作成する
セクションタイトル: 新しいAstroプロジェクトを作成するパッケージマネージャでcreate astro
コマンドを実行し、“empty”テンプレートを選択して新しいプロジェクトを作成します。
npm create astro@latest
pnpm create astro@latest
yarn create astro@latest
インテグレーションと依存関係を追加する
セクションタイトル: インテグレーションと依存関係を追加するastro add
コマンドでReactインテグレーションを導入します。TailwindやMDXが必要なら同時に指定できます。
npx astro add reactnpx astro add react tailwind mdx
pnpm astro add reactpnpm astro add react tailwind mdx
yarn astro add reactyarn astro add react tailwind mdx
CRAが追加のNPMパッケージを必要としている場合は、それらを新しいAstroプロジェクトのpackage.json
に追記し、インストールしてください。多くのReact依存はAstroでも互換性がありますが、すべてが動作するとは限りません。
既存アプリのファイルを追加する
セクションタイトル: 既存アプリのファイルを追加する既存CRAプロジェクトのソースフォルダ(components
、hooks
、styles
など)を構造を保ったままsrc/cra-project/
にコピーし、.js
は.jsx
または.tsx
へリネームします。設定ファイルはコピーせず、Astro側のastro.config.mjs
やtsconfig.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 />
を描画します。
---import App from '../cra-project/App.jsx';---<App client:load />
アプリをインタラクティブに動かすには、クライアントディレクティブ の指定が必要です。AstroはReactアプリをまず静的HTMLとしてビルドし、client:~
が付いたコンポーネントだけをクライアント側で実行します。
client:load
:サーバー側でレンダリングした後、ページの読み込み時にすぐクライアントで起動します。client:only="react"
:サーバー側レンダリングをせず、完全にクライアントサイドでのみ実行します。
CRAをAstroに変換する
セクションタイトル: CRAをAstroに変換する既存アプリをAstroに組み込んだ後、次はアプリ自体をAstroへ変換していきます。
基本構造にはAstro HTMLテンプレートコンポーネントを使い、インタラクティブな部分には個別のReactコンポーネント(場合によってはそれ自体が小さなアプリになっていることもあります)をインポートして配置します。
移行のアプローチはプロジェクトごとに異なりますが、動作中のアプリを中断せず段階的に進められます。無理のないペースで個別の機能を変換し、時間をかけて徐々にAstroコンポーネントで動かす範囲を広げましょう。
Reactアプリを変換する際には、どのReactコンポーネントをAstroコンポーネントとして書き直すかを決めます。制約は次のとおりです。AstroコンポーネントはReactコンポーネントをインポートできますが、Reactコンポーネントは他のReactコンポーネントのみをインポートしなければなりません。
---import MyReactComponent from '../components/MyReactComponent.jsx';---<html> <body> <h1>Astroから直接Reactコンポーネントを使おう!</h1> <MyReactComponent /> </body></html>
AstroコンポーネントをReactコンポーネント内でインポートするのではなく、1つのAstroコンポーネントの中にReactコンポーネントをネストすることもできます。
---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コンポーネント について学んでおくと、移行がスムーズになります。
JSX vs Astro
セクションタイトル: JSX vs Astro以下に、CRAコンポーネントと対応するAstroコンポーネントの例を示します。
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;
---import Header from './Header.astro';import Footer from './Footer.astro';import './layout.css';const res = await fetch('https://api.github.com/repos/withastro/astro')const json = await res.json();const message = json.message;const stars = json.stargazers_count || 0;---<Header /><p class="banner">Astro has {stars} 🧑🚀</p><Footer /><style> .banner { background-color: #f4f4f4; padding: 1em 1.5em; text-align: center; margin-bottom: 1em; }</style>
JSXファイルから.astroファイルへの変換
セクションタイトル: JSXファイルから.astroファイルへの変換以下は、CRAの.js
コンポーネントを.astro
コンポーネントへ変換する際のポイントです。
- 既存のCRAコンポーネント関数が返すJSXを、HTMLテンプレートのベースとして利用します。
{children}
やclassName
など、Astro構文リファレンスをAstro構文またはHTML標準属性へ置き換えます。- import文を含む必要なJavaScriptはすべて
コードフェンス
(---
)内へ移動します。※条件付きレンダリングに使うJavaScriptはテンプレート内に直接記述できます。 - 追加プロパティはAstro.props (EN)で取得します。
- インポートしているコンポーネントを
.astro
へ変換するか検討します。現在のままReactコンポーネントとして残すこともできますが、インタラクティブ性が不要な場合は将来的に.astro
へ書き換えると軽量化できます。 useEffect()
で行っていたデータ取得は、import文やimport.meta.glob()
でローカルファイルを読み込むか、fetch()
で外部データを取得する方法へ置き換えます。
テストの移行
セクションタイトル: テストの移行Astroは静的HTMLを出力するため、ビルド後のファイルを使ったE2Eテスト(エンドツーエンドテスト)が可能です。既存のE2Eテスト(JestやPlaywrightなど)が、CRAサイトのマークアップを忠実に再現できていれば、そのまま動くケースも多いでしょう。また、React Testing LibraryやJestをインポートしてAstro上でReactコンポーネントのテストを行うことも可能です。 詳細は テストガイド を参照してください。
参照: CRAをAstroに変換
セクションタイトル: 参照: CRAをAstroに変換CRAのインポートをAstroに変換
セクションタイトル: CRAのインポートをAstroに変換ファイルインポートを必ず正しい相対パスで記述します。インポートエイリアスを使うか、フルパスを書くかのいずれかです。
.astro
を含む一部のファイル型は拡張子を省略できません。拡張子まで明示してインポートしてください。
---import Card from '../../components/Card.astro';---<Card />
CRAのchildren
プロップスをAstroへ
セクションタイトル: CRAのchildrenプロップスをAstroへ{children}
をAstroの<slot />
に置き換えます。Astroでは{children}
を関数プロップとして受け取る必要はなく、子要素は自動的に<slot />
へ描画されます。
------export default function MyComponent(props) { return ( <div> {props.children} </div> );}
<div> <slot /></div>
複数の子要素を渡すReactコンポーネントは、名前付きスロットを使ってAstroへ移行できます。 詳しくはスロットの使い方を参照してください。
CRAのデータフェッチ方法をAstroに置き換える
セクションタイトル: CRAのデータフェッチ方法をAstroに置き換えるCreate React App でのデータ取得はAstroでも似ていますが、いくつか違いがあります。
サイドエフェクトフック(useEffect()
)によるローカルファイル取得は削除し、代わりにimport.meta.glob()
またはgetCollection()
/getEntry()
を使います。
リモートデータはfetch()
を利用します。
これらの処理はフロントマター(---
内)でtop-level awaitを使って実行します。
---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];---
import.meta.glob()
によるローカルファイル取得: /ja/guides/imports/#globパターン- Collections APIのクエリ: /ja/guides/content-collections/#コレクションのクエリ
- リモートデータのフェッチ: /ja/guides/data-fetching/
CRAのスタイリングをAstroへ
セクションタイトル: CRAのスタイリングをAstroへAstroではCSS-in-JSライブラリ(例:styled-components)がそのまま使えない場合があります。必要に応じて他のCSS手法へ置き換えてください。
- インラインスタイルオブジェクト(
style={{ fontWeight: "bold" }}
)はHTMLのインライン属性(style="font-weight: bold;"
)へ変換します。 - または、Astroの
<style>
タグを使ってスコープ付きCSSを記述します。
<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 で質問してください。
コミュニティリソース
セクションタイトル: コミュニティリソースもし、Create React AppをAstroに移行するのに役立つビデオやブログ記事を見つけた見つけた、あるいは自分で作成した役立つ動画やブログ記事があれば、このリストに追加してください。