[Astro #37] Cloudflare Pagesによるミラーサイト構築記録:Netlifyの限界を超えた4,000アセットの同期
はじめに
本記事では、500件以上の記事と4,000を超える静的アセットを抱える大規模なAstroプロジェクトにおいて、Cloudflare Pagesを用いた「ミラーサイト」の構築手順を解説します。
従来のホスティング環境(Netlify等)でのビルド時間制限やリソース不足という不条理を突破し、いかにして別系統の高速なインフラへ「遷都」し、冗長性を確保したのか。その過程で直面したメモリ不足(OOM)や依存関係の解決、そして数分で完了するサブドメイン運用の設定までを記録します。
前回の記事:
[Astro #36] Webターミナルへのモデム通信プロトコル(ATコマンド)エミュレーションの実装 // PROTOCOL.LAIN
WebターミナルにおけるATコマンド通信プロトコルの実装記録。Audio APIのonendedイベントを利用してハンドシェイク音によるネゴシエーション状態を管理し、接続確立後に3D描画側(VRM)のアニメーションを非同期でキックする状態遷移アーキテクチャについてまとめました。
lain-lab.com1. Cloudflare Pagesの初期設定とビルド方法
まずはCloudflareのダッシュボードから、通常通りGitHubリポジトリを連携して初期設定を行います。
- プロジェクトの作成:
Workers & Pages>Pages>Connect to Gitから対象のAstroプロジェクトを選択します。
- ビルド設定 (Build settings): 以下の通りに設定します。
- Framework preset:
Astro(自動認識されない場合は手動で選択) - Build command:
npm run build - Build output directory:
dist
- Framework preset:
- Save and Deploy: 設定を保存して初回デプロイを実行します。
2. デプロイ時に発生したトラブルと対処法
Netlifyから移行したAstroプロジェクトをCloudflareでビルドする際、環境の違いやプロジェクト規模によっていくつか特有のエラーが発生します。
トラブル①:依存関係の衝突でインストールが失敗する (ERESOLVE)
【症状】
ビルドログの初期段階で npm ERR! ERESOLVE や Fix the upstream dependency conflict と表示され、ビルドが停止する。
(例:@vite-pwa/astro と astro 本体のバージョン不一致など)
【原因】 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用のアダプターに変更します。
- ローカルでパッケージをインストール:
npm install @astrojs/cloudflare 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)が有効です。
【手順】
- Wranglerのインストール ターミナルで以下のコマンドを実行し、グローバルにインストールします。
npm install -g wrangler
- ローカル環境でのビルド ご自身の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
- 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 を利用している場合、設定は数分で完了します。
設定手順
- カスタムドメインの追加:
Cloudflare Pages プロジェクトの
Custom domainsタブからSet up a custom domainをクリックします。
- サブドメインの指定:
mirror.example.comのように、ミラー用に使用したいサブドメインを入力します。
- DNSレコードの自動構成:
Confirm new DNS record画面が表示されるので、内容(CNAMEレコードがpages.devのホスト名に向いていること)を確認し、Activate domainをクリックします。
- SSL/TLSの自動発行:
ステータスが
Initializingになり、Cloudflare によって SSL 証明書の発行とルーティングの確立が全自動で行われます。
メリット
この構成をとることで、メインサイトに影響を与えることなく、Cloudflare のエッジネットワークを活かした高速なミラーサイトを構築できます。今回のように 4,000 件を超えるアセットを持つ大規模プロジェクトでも、DNS の反映は極めて迅速(数分〜数十分)に行われます。
注釈:
Netlify Forms などのプラットフォーム固有機能を利用している場合、Cloudflare へのミラーリング後はそれらの機能が動作しなくなります。必要に応じて Formspree や Cloudflare Workers への差し替えを検討してください。