[Astro #07] HugoからAstroへの移行とビルド最適化・クローリング検証
はじめに
約1年間運用したHugoベースのサイトから、Astro + React + MDXによるアーキテクチャへ移行を行った。同時にドメインを lain-lab.com へ移管している。
本記事では、静的サイトジェネレーター(SSG)としてHugoからAstroへ移行した技術的な背景、移行プロセスで発生したビルドエラーとその解決策、および移行直後の検索エンジンのクローリング状況について記録する。
Astro
Astro builds fast content sites, powerful web applications, dynamic server APIs, and everything in-between.
astro.build
React
React is the library for web and native user interfaces.
react.dev
MDX
MDX lets you use JSX in your markdown content.
mdxjs.comHugoからAstroへ移行する具体的なメリット
Hugoはビルド速度において極めて優秀なツールだが、当サイトの要件(Three.jsやWebXRを用いたインタラクティブコンテンツの配置)においてはいくつか構造的な制約があった。旧Hugoユーザーの視点から、Astro(特にMDXとアイランドアーキテクチャ)を採用した具体的なメリットを挙げる。
1. MDXによるシームレスなコンポーネント統合
Hugoでは、Markdown内に複雑なJavaScriptコンポーネントを埋め込む場合、Shortcodeを利用する必要がある。しかし、Shortcodeは基本的に文字列ベースのテンプレート処理であるため、Reactコンポーネントに複雑な状態(Props)を渡したり、ライフサイクルを管理したりする用途には適していなかった。
Astro + MDX環境では、Markdownファイル内で直接JSXを記述し、Reactコンポーネントをインポート・マウントできる。例えば、以下のように記述するだけでReact Three Fiber (R3F) のオブジェクトを記事内に配置可能である。
import RubiksCube from "../../components/three/RubiksCube";
<div style={{ height: "600px", width: "500px", margin: "2rem 0" }}>
<RubiksCube client:load />
</div>
実行結果:
2. アイランドアーキテクチャによるパフォーマンス最適化
上記コードの client:load ディレクティブに代表されるAstroの「アイランドアーキテクチャ」も大きなメリットである。
静的なテキストコンテンツはサーバーサイドでHTMLとして事前生成(SSG)されつつ、3Dモデルなどのインタラクティブなコンポーネント部分のみをクライアントサイドでハイドレーション(JavaScriptの有効化)させることができる。これにより、Hugoの強みであった「静的ページの配信速度」を維持したまま、リッチなフロントエンド技術を局所的に導入することが可能になった。
移行プロセスにおける課題と対応
551件のアーカイブ記事と2,000回以上のコミット履歴を持つリポジトリの移行にあたり、いくつかの技術的課題が発生した。
課題1: Gitリポジトリの肥大化(2.45GBのデブリ)
長期間の開発により、.git ディレクトリが2.45GBまで肥大化していた。原因は、過去のコミットに含まれていた node_modules、ビルド成果物(.next, dist)、検証用の3Dアセット(.glb等)、および不要なSSL証明書などのバイナリファイル群である。
- 対応:
git filter-repoを使用し、対象の拡張子やディレクトリをコミット履歴全体から削除。結果としてリポジトリサイズを数十MBまで軽量化し、CI/CD環境でのクローン時間を大幅に短縮した。
課題2: getStaticPathsにおけるENOENTエラー
Hugo時代のディレクトリ構造(複雑なカテゴリ分類など)を維持したままAstroの動的ルーティングシステムに移行した際、ビルド時にENOENT(Error NO ENTry)エラーが多発した。
- 対応: Astroはビルド時に厳密にパスを評価するため、参照先のディレクトリが存在しないとエラーになる。これを回避するため、ファイル生成ロジック内に防弾処理として
fs.mkdirSync(dir, { recursive: true })を追加し、ディレクトリが存在しない場合はビルドプロセス中に動的生成するよう修正した。
課題3: ViteのHTTPS設定とCI環境の競合
ローカルのWebXR開発用に自己署名証明書を用いたHTTPS化をVite設定(server.https)にハードコーディングしていたため、証明書ファイルが存在しないNetlifyのビルド環境でエラーが発生した。
- 対応:
fs.existsSyncを使用して、実行環境(ローカルかCI環境か)における証明書の有無を判定。存在しない場合はhttps: falseにフォールバックする条件分岐を実装し、環境の差異を吸収した。
課題4: Netlify環境でのヒープメモリ不足 (OOM)
ローカルでの検証後、Netlifyへデプロイした際に以下のV8エンジンのメモリ不足エラーが発生し、ビルドが停止した。
FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory
原因は、551件のMDXファイルのパース処理に加え、Shikiによる全ページのシンタックスハイライト処理(静的生成)がNetlifyのデフォルトのメモリ制限を超過したことである。
- 対応: Netlifyの環境変数に以下を設定し、Node.jsプロセスに割り当てるメモリの上限を4GBに拡張した。これにより、635ページ分の全ビルドが正常に完了するようになった。
NODE_OPTIONS=--max-old-space-size=4096
課題5: MDXパーサーとLaTeX構文の衝突
ビルドプロセスの最終段階で、以下の参照エラーが発生した。
ReferenceError: bmatrix is not defined
- 原因と対応: 記事内に記述された線形代数のLaTeX構文(
\begin{bmatrix}など)が原因。検証の過程で一時的に数式プラグイン(remark-math,rehype-katex)を無効化していたため、AstroのMDXパーサーが{bmatrix}をJavaScriptの変数として評価しようとしていた。設定ファイルでプラグインを再有効化し、Markdown内の数式ブロックが正しくAST変換されるように修正した。
課題6: ドメイン移行に伴うSEOリスクと大容量アセットの配信負荷
新ドメイン lain-lab.com への移行にあたり、旧ドメインからのSEO評価を損失なく引き継ぐための適切なリダイレクト処理が必要であった。同時に、Three.jsを用いた3Dモデル(.glbファイル)や高解像度テクスチャなど、リッチなフロントエンド実装によって増大したペイロードの配信最適化もインフラレイヤーにおける大きな課題となった。
- 対応: DNS管理およびCDNレイヤーとしてNetlifyの前段にCloudflareを導入し、以下の構成でインフラ全体の最適化を図った。
- エッジレベルでの301リダイレクト: 最も重要な旧ドメインからの転送処理を、Astroのアプリケーション層やNetlifyのEdge Functionsではなく、CloudflareのPage Rules(またはBulk Redirects)へ移譲した。リクエストがオリジンに到達する前のエッジノードで高速に処理されるため、クローラーへのレスポンスタイムを最小化している。
- CDNキャッシュと負荷分散: 容量の大きい静的アセット(3Dモデル等)をCloudflareのエッジサーバーにキャッシュさせる戦略をとった。これにより、Netlify側の帯域幅消費を大幅に抑制しつつ、TTFB(Time to First Byte)を改善している。
- SSL/TLSの厳格化: Cloudflareの「フル(厳密)」モードを適用し、クライアントからエッジ、そしてNetlifyのオリジンサーバー間のすべての通信経路をエンドツーエンドで完全に暗号化するセキュアな構成を確立した。
新ドメインへの移行と昨日・今日のクローリング状況
技術的課題の解消後、新ドメイン lain-lab.com への本番移行とSEOの設定を行った。
- サイトマップの自動生成:
@astrojs/sitemapプラグインを導入し、ビルド時にsitemap-index.xmlが自動生成されるパイプラインを構築。 - DNS認証: Google Search Console(GSC)にて、TXTレコードを用いたドメインプロパティの認証を完了。
昨日〜本日にかけてのクローリングログ(ステータス報告): 昨日GSCからサイトマップを送信し、本日のサーバーログおよびGSCの「ページインデックス」レポートを確認したところ、以下のような挙動が観測されている。
- 検出ステータス: Googlebotによりサイトマップ内の551件のURLが正常に検出された(
URL is known to Google)。 - クロール・インデックス状況: 本日時点で約120件のアーカイブ記事に対する初回クロールが走っており、ステータスコード200を返していることをログで確認。旧ドメインからの301リダイレクトも正常に機能しており、「クロール済み - インデックス未登録」から順次インデックスへの登録が進行している段階である。
まとめ
HugoからAstroへの移行は、単なるビルドツールの変更ではなく、MarkdownコンテンツとReactエコシステム(R3Fなど)を統合するためのアーキテクチャ刷新であった。
Gitのクリーンアップ、OOMエラーの回避、MDX特有のパース処理への対応など複数の技術的障壁があったものの、最終的に「静的サイトの速度」と「動的コンポーネントの柔軟性」を両立したシステムを構築できた。現在、検索エンジンによるクロールも正常に進行しており、運用基盤としての準備は完全に整ったと言える。
COMM_LOG: astro-07-hugo-to-astro-migration-complete