[Astro #37] Cloudflare Pagesによるミラーサイト構築記録:Netlifyの限界を超えた4,000アセットの同期

[Astro #37] Cloudflare Pagesによるミラーサイト構築記録:Netlifyの限界を超えた4,000アセットの同期

はじめに

本記事では、500件以上の記事と4,000を超える静的アセットを抱える大規模なAstroプロジェクトにおいて、Cloudflare Pagesを用いた「ミラーサイト」の構築手順を解説します。

従来のホスティング環境(Netlify等)でのビルド時間制限やリソース不足という不条理を突破し、いかにして別系統の高速なインフラへ「遷都」し、冗長性を確保したのか。その過程で直面したメモリ不足(OOM)や依存関係の解決、そして数分で完了するサブドメイン運用の設定までを記録します。

前回の記事:

1. Cloudflare Pagesの初期設定とビルド方法

まずはCloudflareのダッシュボードから、通常通りGitHubリポジトリを連携して初期設定を行います。

  1. プロジェクトの作成: Workers & Pages > Pages > Connect to Git から対象のAstroプロジェクトを選択します。
  1. ビルド設定 (Build settings): 以下の通りに設定します。
    • Framework preset: Astro (自動認識されない場合は手動で選択)
    • Build command: npm run build
    • Build output directory: dist
  1. Save and Deploy: 設定を保存して初回デプロイを実行します。

2. デプロイ時に発生したトラブルと対処法

Netlifyから移行したAstroプロジェクトをCloudflareでビルドする際、環境の違いやプロジェクト規模によっていくつか特有のエラーが発生します。

トラブル①:依存関係の衝突でインストールが失敗する (ERESOLVE)

【症状】 ビルドログの初期段階で npm ERR! ERESOLVEFix the upstream dependency conflict と表示され、ビルドが停止する。 (例:@vite-pwa/astroastro 本体のバージョン不一致など)

【原因】 Cloudflareのビルド環境のnpmバージョンと、Netlify環境との間で、ピア依存関係(peer dependencies)のチェックの厳密さが異なるために発生します。

【対処法】 環境変数(Environment variables)を設定し、依存関係のエラーを無視してインストールを強行させます。

  • Variable name: NPM_CONFIG_LEGACY_PEER_DEPS
  • Value: true

トラブル②:ビルド中にメモリ不足でクラッシュする (OOM)

【症状】 記事数が数百件を超えるプロジェクトにおいて、ビルドの途中で FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory というエラーが出て失敗する。

【原因】 Astroが大量のMarkdownファイルをパース・静的生成する際、CloudflareビルドコンテナのデフォルトのNode.jsメモリ上限を超過してしまうためです。

【対処法】 環境変数を追加し、Node.jsに割り当てるメモリ上限を拡張します(以下は8GBを割り当てる例)。

  • Variable name: NODE_OPTIONS
  • Value: --max-old-space-size=8192

トラブル③:デプロイは成功したが、文字やCSSが表示されない

【症状】 デプロイログに Success と表示されているにもかかわらず、実際のURLを開くとCSSが適用されておらず、文字が見えないなどの表示崩れが起きる。

【原因】 astro.config.mjs に、Netlify用のアダプター(@astrojs/netlify)が残っていることが原因です。Cloudflare上でNetlify用のビルドが走り、URLパスやアセットの解決に齟齬が生じています。

【対処法】 Cloudflare用のアダプターに変更します。

  1. ローカルでパッケージをインストール: npm install @astrojs/cloudflare
  2. astro.config.mjs を以下のように修正してPushします。
import { defineConfig } from "astro/config";
// Netlifyのアダプターを削除し、Cloudflareをインポート
import cloudflare from '@astrojs/cloudflare';

export default defineConfig({
  // adapterを入れ替える
  adapter: cloudflare(),
  // その他の設定...
});

3. Wranglerを使ったローカルデプロイ方法

Cloudflare側のビルド環境でどうしてもエラーが解決しない場合や、ローカルマシンのリソース(メモリなど)を使って高速にビルドしたい場合は、CLIツール「Wrangler」を使用した直接デプロイ(Direct Upload)が有効です。

【手順】

  1. Wranglerのインストール ターミナルで以下のコマンドを実行し、グローバルにインストールします。
npm install -g wrangler
  1. ローカル環境でのビルド ご自身のPCでビルドを実行します。メモリ不足になる場合はローカルでもオプションを付与します。
# Windows (PowerShell) の場合
$env:NODE_OPTIONS = "--max-old-space-size=8192"
npm run build

# Mac / Linux の場合
NODE_OPTIONS="--max-old-space-size=8192" npm run build
  1. Cloudflare Pagesへの直接デプロイ dist ディレクトリが生成されたら、以下のコマンドで一括アップロードします。(<project-name> は実際のCloudflare Pagesのプロジェクト名に置き換えてください)
npx wrangler pages deploy ./dist --project-name=<project-name>

※初回実行時はブラウザが立ち上がり、Cloudflareアカウントへのログインと認証が求められます。

この方法であれば、CloudflareのCI/CDを使わずに静的ファイルのみを確実に配信できるため、ビルドエラーの切り分けにも役立ちます。

4. ミラーサイト(サブドメイン)の運用設定

メインサイトを Netlify で運用しつつ、Cloudflare Pages をミラーサイトやバックアップとして公開する場合、サブドメインを利用したカスタムドメイン設定が有効です。Cloudflare DNS を利用している場合、設定は数分で完了します。

設定手順

  1. カスタムドメインの追加: Cloudflare Pages プロジェクトの Custom domains タブから Set up a custom domain をクリックします。
  1. サブドメインの指定: mirror.example.com のように、ミラー用に使用したいサブドメインを入力します。
  1. DNSレコードの自動構成: Confirm new DNS record 画面が表示されるので、内容(CNAMEレコードが pages.dev のホスト名に向いていること)を確認し、Activate domain をクリックします。
  1. SSL/TLSの自動発行: ステータスが Initializing になり、Cloudflare によって SSL 証明書の発行とルーティングの確立が全自動で行われます。

メリット

この構成をとることで、メインサイトに影響を与えることなく、Cloudflare のエッジネットワークを活かした高速なミラーサイトを構築できます。今回のように 4,000 件を超えるアセットを持つ大規模プロジェクトでも、DNS の反映は極めて迅速(数分〜数十分)に行われます。

注釈:

Netlify Forms などのプラットフォーム固有機能を利用している場合、Cloudflare へのミラーリング後はそれらの機能が動作しなくなります。必要に応じて Formspree や Cloudflare Workers への差し替えを検討してください。