Migrate from Next.js to Astro
Next.js製のブログメインのサイトをAstroに移行する作業のメモ
2025/02 加筆・修正
概要
Must Have
- ブログはmarkdown
- カテゴリー、タグあり
- 本文にコードブロック、目次、見出しのリンク
- 多言語
Nice to Have
- CodePenなどの埋め込み対応
- 動的にOG Imageを生成
- markdown内のリンクを内部/外部に対応
- rss
- Search form
- CMS
Astro開発環境を整える
1. Astroのインストール
一旦フォルダ内を空にしてAstroの開発環境を整える
npm create astro@latest
A basic, minimal starter (recommended) を選択
インストールが完了後、localでの表示を確認

2. ESLint, Prettier の設定
/* ESLint with TypeScript */
npm install --save-dev eslint eslint-plugin-astro
npm install --save-dev @typescript-eslint/parser
/* Prettier */
npm i --save-dev prettier prettier-plugin-astro
個人的に追加
/* For ESLint */
npm install --save-dev @typescript-eslint/eslint-plugin
npm install --save-dev eslint-plugin-import
/* For Prettier */
npm install --save-dev eslint-config-prettier
各種設定ファイルを既存から移動(一部Astro用に書き換える)
- .eslintignore
- .eslintrc.json(React用のルールは一旦排除)
- .prettierignore
- .prettierrc(以下を追加)
{
...
"plugins": ["prettier-plugin-astro"],
"overrides": [
{
"files": "*.astro",
"options": {
"parser": "astro"
}
}
]
}
3. React
npx astro add react
4. importのパスを絶対パスにする
tsconfig.json に以下を追加する
{
...
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
}
}
}
5. リセットCSS, SCSS
npm install sass
npm install modern-normalize
既存のファイルを移動して読み込む
// Layout.astro
---
import "node_modules/modern-normalize/modern-normalize.css";
import "@/styles/global.scss";
---
その他
静的ファイルを移動
- favicon.ico → public/
- robots.txt → public/
- manifest.json → public/
Google Analytics
ライブラリをインストール
npx astro add partytown
Webフォントの使用
- public/ に fonts/を作成してfontファイルを追加する
- src/styles/ に fonts.css を作成
- Layout.astro でimportする
多言語化対応
Next.jsとの大きな違いは /pages/ 以下
Next.jsのときは基本的にcontents以外のファイルは言語ごとに持っている必要がなかったが、Astroでは /pages/ 配下も全て言語に対応したファイルが必要。
デフォルト言語でURLに /ja/ が入るのを許容すればDynamic routesでファイルを共通化できそう。ただデフォルト言語はprefix入れたくない。/にアクセスしたら /ja/にリダイレクトさせる形で共通化させるので、/ja/を/にリダイレクトはできない。
コンテンツ部分をまるっとコンポーネント化して、pages 内の各言語ファイルではそれを読み込むだけにする。
公式のドキュメントに沿って設定する
Layout.astro
Next.js では以下のファイルに記述されている主に <head> 内のものとheader, footerの読み込み
- src/pages/_document.tsx
- src/pages/_app.tsx
- src/components/Layout.tsx (全ページで読み込まれるコンポーネント)
Todo
- Elements
- Accordion
- Ads
-
LocaleSwitcher=> spec out ScrollTo → JSで書き直す- Share
- Head
SEO.tsx → BaseHeadにする
-
LayoutFooterHeaderLayout-
Navigation→ headerのみで使用のため削除
-
Page→ 削除ContentBlockTitle
- Post
- CategoryList
- PostDate
- PostDetail
- PostFooter
- PostListing
- PostNoTranslate
- PostTags
- TagList
-
Project→ 削除ProjectCardProjectList
-
Template→ 削除TemplateCardTemplateList
-
UserUserInfoUserLogo
メモ
React.Fragment → Fragment に置き換え可
childrenへのcss
Reactで以下のようにchildrenへのcssを親コンポーネント側で指定している場合、
childrenのdivに width: 50% は適用される
<div css={list}>
{children}
</div>
const list = css`
& > div {
width: 50%;
}
`;
Astroへの書き換え後
<slot /> のdivへスタイルは適用されない
<div class="list">
<slot />
</div>
<style>
.list {
& > div {
width: 50%;
}
}
</style>
一部コンポーネントにReactを使う
npx astro add react
npm install @astrojs/react
astro.config.mjs を自動的に書き換えるか確認があるので(Y)を選択
Reactコンポーネントを読み込む
---
import SomeComponent from "../SomeComponent.tsx";
---
<SomeComponent client:visible />
JavaScript
cssと同じ要領で <script></script> 内に記述する
<button id="button">
ボタン
</button>
<script>
const button = document.getElementById("button");
button?.addEventListener("click", () => {
window.scrollTo({ top: 0, behavior: "smooth" });
});
</script>
tsxからastroへの書き換え
基本的に必要な書き換え
import を --- で挟む
+ ---
import { Card } from "@/src/components/Card.astro";
+ ---
style(CSS)
- className を
classに書き換え - cssの記述を
<style></style>に移動(CSS-in-JSの場合)
- <div className="card">
+ <div class="card">
...
+ <style>
+ .card {
+ ...
+ }
+ </style>
propsとReact関連の書き換え
- React 関連や不要なimportを削除
- interface でpropsの型を定義
- const でコンポーネント内で使用するpropsを定義
-
return ()内のhtml以外を削除
---
- import { ReactElement, ReactNode } from "react";
...
+ interface Props {
+ title: string;
+ }
+ const { title } = Astro.props;
---
- const Card = ({ title }: Props): ReactElement => {
- return (
<div>{title}</div>
- );
- }
- export default ProjectList;
markdownファイルの読み込み
Next.js
- markdownファイルのディレクトリを取得
- 表示に必要なデータを取得
- 並べ替え
- 件数絞り込み
をそれぞれJavaScriptで書いていたのをAstroでは
上2つはgetCollection()のみで置き換えられるのでかなり記述が少なく
サイトマップを追加
npx astro add sitemap
configにサイトURLを追加(追加しない場合sitemap-index.xmlは生成されない)
// astro.config.mjs
...
import sitemap from "@astrojs/sitemap";
export default defineConfig({
site: "https://sample.com",
integrations: [sitemap()],
});
npm run build でdist内にxmlファイルが作成されるのを確認
Layout.astroで読み込み
// Layout.astro
...
<head>
<link rel="sitemap" href="/sitemap-index.xml" />
</head>
サポートされていない画像
投稿記事内で読み込んでいたgif画像がlocalでは問題ないが、デプロイするとエラーになるため削除した