kt-tech.blog

画像

【トラブルシューティング】Cloudflare Pages デプロイCI/CDで踏んだ地雷5選

Share
📌
📌 概要: Cloudflare PagesにNext.jsをGitHub Actions経由でデプロイするCI/CDを構築した際に踏んだ地雷を5つ紹介。.vercel/outputが見つからない、peer dep conflict、nodejs_compat未設定、環境変数の罠、日本語コミットメッセージ拒否など、全てのエラーと解決策をまとめました。

はじめに

Cloudflare PagesへのNext.jsデプロイをGitHub Actionsで自動化しようとしたところ、ビルドは通るのにデプロイが通らない、デプロイは通るのにサイトが動かない、という問題に連続で遭遇した。

1つずつ解決していった記録をまとめる。

この記事でわかること

  • @cloudflare/next-on-pagesのビルドフローの仕組み

  • peer dependency conflictの根本原因と解決策

  • Cloudflare Pages固有の設定(nodejs_compat, 環境変数)

  • wranglerコマンドの落とし穴

対象読者

  • Cloudflare PagesにNext.jsをCI/CDでデプロイしたい方

  • GitHub Actionsでのデプロイが失敗して困っている方

前提条件

  • Next.js 15.x + @cloudflare/next-on-pages

  • GitHub Actions

  • wrangler CLI

地雷1: .vercel/output/config.json が見つからない

エラー

⚡️ Could not read the '.vercel/output/config.json' file.
⚡️ Please report this at https://github.com/cloudflare/next-on-pages/issues.

原因

npm run build(= next build)は.next/に出力する。@cloudflare/next-on-pages --skip-build.vercel/output/を前提とする。この2つは互換性がない。

解決策

--skip-buildを外して、next-on-pagesにビルドを一括で任せる。

# ❌ NG: 2段階ビルド
- run: npm run build
- run: npx @cloudflare/next-on-pages --skip-build

# ✅ OK: next-on-pagesに一括
- run: npx @cloudflare/next-on-pages
  env:
    NOTION_API_KEY: ${{ secrets.NOTION_API_KEY }}

地雷2: peer dependency conflict(ERESOLVE)

エラー

npm error ERESOLVE could not resolve
npm error peer next@"~15.0.8 || ~15.1.12" from @opennextjs/cloudflare@1.17.1

原因

next-on-pagesは内部でnpx vercel buildを実行し、そこでnpm installが走る。このとき.npmrclegacy-peer-deps設定が効かず、peer dependency conflictが発生。

不要な@opennextjs/cloudflarepackage.jsonに残っていたのも原因の一つ。

解決策

  1. 不要な依存を削除(@opennextjs/cloudflare, esbuild等)

  2. .npmrcファイルをプロジェクトルートに追加

legacy-peer-deps=true

これでvercel build内部のnpm installでもlegacy-peer-depsが効く。

地雷3: nodejs_compat 未設定で503

エラー

サイトにアクセスすると以下のHTMLが返る:

Error - no nodejs_compat compatibility flag

原因

Cloudflare PagesプロジェクトにNode.js互換フラグが設定されていない。Next.jsはNode.js APIを使うため必須。

解決策

Cloudflare API経由で設定:

curl -X PATCH "https://api.cloudflare.com/client/v4/accounts/{account_id}/pages/projects/{project_name}" \
  -H "Authorization: Bearer {api_token}" \
  -H "Content-Type: application/json" \
  -d '{"deployment_configs":{"production":{"compatibility_flags":["nodejs_compat"],"compatibility_date":"2024-09-23"}}}'

またはダッシュボードから: Workers & Pages → プロジェクト → Settings → Functions → Compatibility flags

地雷4: Pages環境変数が未設定で500

エラー

TOPページは表示されるが、記事詳細ページでInternal Server Error

原因

GitHub Actionsのビルド時にはsecretsで環境変数を渡しているが、Pagesのランタイム(Worker実行時)には環境変数が設定されていない。Edge RuntimeのSSRではリクエスト時にNotion APIを呼ぶため、ランタイムにもNOTION_API_KEY等が必要。

解決策

Cloudflare API経由でPages環境変数を設定:

curl -X PATCH "https://api.cloudflare.com/client/v4/accounts/{account_id}/pages/projects/{project_name}" \
  -H "Authorization: Bearer {api_token}" \
  -H "Content-Type: application/json" \
  -d '{"deployment_configs":{"production":{"env_vars":{"NOTION_API_KEY":{"value":"[API_KEY]","type":"secret_text"},"NOTION_DATABASE_ID":{"value":"[DB_ID]","type":"plain_text"}}}}}'
📌
📌 ポイント: ビルド時の環境変数(GitHub Secrets)とランタイムの環境変数(Pages Settings)は別物。両方設定が必要。

地雷5: 日本語コミットメッセージで deploy 失敗

エラー

A request to the Cloudflare API failed.
Invalid commit message, it must be a valid UTF-8 string. [code: 8000111]

原因

wrangler pages deployがgitのコミットメッセージを自動取得してCloudflare APIに送信する。日本語のコミットメッセージがCloudflare API側で拒否される。

解決策

--commit-messageオプションでASCII文字のみのメッセージを明示的に指定:

- name: Deploy to Cloudflare Pages
  run: npx wrangler pages deploy .vercel/output/static \
    --project-name=my-project \
    --commit-dirty=true \
    --commit-message="deploy ${{ github.sha }}"

最終的なワークフロー

name: Deploy to Cloudflare Pages
on:
  push:
    branches: [main]
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: npm
      - run: npm ci --legacy-peer-deps
      - name: Build for Cloudflare Pages
        run: npx @cloudflare/next-on-pages
        env:
          NOTION_API_KEY: ${{ secrets.NOTION_API_KEY }}
          NOTION_DATABASE_ID: ${{ secrets.NOTION_DATABASE_ID }}
      - name: Deploy
        run: npx wrangler pages deploy .vercel/output/static --project-name=my-project --commit-dirty=true --commit-message="deploy ${{ github.sha }}"
        env:
          CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
          CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}

Tips

📌
📌 Tips
📌
  • .npmrcはプロジェクトルートに置く。 vercel buildが内部でnpm installを走らせる際にも読み込まれる
📌
  • nodejs_compatと環境変数はデプロイ後に設定しても再デプロイが必要。 設定変更だけでは既存デプロイに反映されない
📌
  • --commit-dirty=trueを付けないと警告が出る。 ビルド生成物がuncommittedとして検出される

まとめ

  • next-on-pagesには--skip-buildを付けず一括ビルドさせる

  • .npmrcでpeer dep conflictを回避

  • nodejs_compatフラグとランタイム環境変数は別途設定が必要

  • 日本語コミットメッセージはwranglerで拒否される

  • 全て解決すれば安定したCI/CDパイプラインが構築できる

アーカイブ