【実録】Next.jsとCloudflare Pagesでのデバッグ奮闘記:Git LFSからCSPエラーまで
August 10, 2025 Next.js Cloudflare Pages Git Debug トラブルシューティング
【実録】Next.jsとCloudflare Pagesでのデバッグ奮闘記:Git LFSからCSPエラーまで
こんにちは!Web開発の現場では、予期せぬエラーとの遭遇は日常茶飯事です。今回は、Next.jsプロジェクトをCloudflare Pagesにデプロイする際に直面した、一連の困難なデバッグプロセスを記録として残します。Git LFSエラーから始まり、Next.jsのビルドエラー、ハイドレーションエラー、そして最終的にCloudflare Pages特有のCSP/Illegal invocationエラーまで、その解決の道のりをご紹介します。
1. Git LFSエラーとの戦い:巨大な node_modules を履歴から消し去る
問題の発端
Next.jsプロジェクトをGitHubにプッシュしようとしたところ、以下のエラーに遭遇しました。
remote: error: File <プロジェクト名>/node_modules/... is 129.50 MB; this exceeds GitHub's file size limit of 100.00 MB
これは、node_modules フォルダが誤ってGitの管理対象になってしまい、GitHubのファイルサイズ制限(100MB)を超過したためでした。
最初の試み:.gitignore と git rm --cached
定番の解決策として、.gitignore に /node_modules を追加し、git rm -r --cached . でインデックスから削除しました。
.gitignore に /node_modules を追記
git add .
git commit -m "fix: .gitignoreを追加"
しかし、プッシュは失敗。Gitの履歴に巨大なファイルが残っている限り、GitHubはプッシュを拒否することが判明しました。
BFG Repo-Cleanerとの格闘(そして断念)
履歴をクリーンアップするため、Git公式も推奨する BFG Repo-Cleaner を試みました。
ミラークローンを作成
git clone --mirror https://github.com/<ユーザー名>/<リポジトリ名>.git
cd <リポジトリ名>.git
BFGの実行(様々なオプションを試すも失敗)
java -jar ../bfg-x.x.x.jar --delete-folders node_modules # フォルダ名指定
java -jar ../bfg-x.x.x.jar --strip-blobs-bigger-than 100M # サイズ指定
java -jar ../bfg-x.x.x.jar -D <ファイル名> # ファイル名指定
...いずれも "No refs to update - no dirty commits found??" で失敗
git gc を実行してリポジリを最適化しても状況は変わらず、BFGでは解決できない稀なケースと判断し、断念しました。
最終手段:禁断の git filter-branch
最後の手段として、Git標準の git filter-branch を使用しました。
【重要】この操作はGit履歴を書き換えるため、必ずリポジリのバックアップを取ってから実行してください。
プロジェクトルートで実行
git filter-branch --force --index-filter 'git rm -r --cached --ignore-unmatch <Next.jsプロジェクトのディレクトリ名>/node_modules' --prune-empty --tag-name-filter cat -- --all
バックアップ参照の削除とリポジリの最適化 PowerShellの場合:
Remove-Item -Recurse -Force .git\refs\original
Linux/macOS/Git Bashの場合:
rm -rf .git/refs/original/
参照ログと不要なデータを削除
git reflog expire --expire=now --all
git gc --prune=now
強制プッシュ
git push origin --force --all
git push origin --force --tags
この操作により、ついに巨大なファイルが履歴から消去され、GitHubへのプッシュが成功しました。
2. Next.jsビルドエラーの連鎖:シンタックスから型まで
Gitの問題が解決したのも束の間、Cloudflare Pagesでのデプロイが失敗。ビルドログには新たなエラーが次々と現れました。
シンタックスエラー
- 原因: 文字列内のアポストロフィ(例:
App's)が原因で、JavaScriptの構文エラーが発生。JSXの閉じタグ忘れ。 - 解決策: 文字列をダブルクォートで囲む、閉じタグを追加するなど、基本的な構文エラーを修正。
TypeScriptの型エラー
- 原因:
getBlogPostがnullを返す可能性を考慮していない。useState([])のように初期化された配列に、ContentfulのEntry型を代入しようとした。console.logがJSX内に残っていた。setAttributeに数値が渡されていた。document.createElementの戻り値の型推論が不適切。
- 解決策:
nullチェックの強化、useState<Entry<any>[]>([]);のように型を明示、console.logの削除、String()で型変換、as HTMLScriptElementで型アサーション。
Cloudflare Pages特有の設定エラー
- Edge Runtime設定:
export const runtime = 'edge';が不足しているルートがあった。 - Node.js Compatibility:
nodejs_compatフラグがCloudflare Pagesの設定で有効化されていなかった。
これらのエラーを一つずつ修正し、Next.jsのビルドはついに成功しました。
3. ランタイムエラーの深淵:CSPとIllegal invocation
ビルドが成功したにもかかわらず、サイトにアクセスすると Application error が表示され、ブラウザコンソールには Content Security Policy of your site blocks the use of 'eval' in JavaScript と TypeError: Illegal invocation が表示されました。
eval エラーとの戦い
- 原因の切り分け:
RichTextRendererのdangerouslySetInnerHTMLを無効化するとevalエラーが消えるが、コンテンツが表示されない。DisqusCommentsや Google AdSense を無効化してもevalエラーが消えない。- Contentfulのブログ記事を完全に空にしても
evalエラーが消えない。
- 結論:
evalエラーは、RichTextRendererのdangerouslySetInnerHTMLを通じてレンダリングされるContentfulのリッチテキスト内のJavaScript、またはCloudflare Pagesの内部処理に起因する可能性が高い。
Illegal invocation エラーとの戦い
- 原因の切り分け:
DisqusCommentsのDOM操作 (createElement,appendChild) やDISQUS.resetの呼び出しでthisのコンテキストが失われる問題が発生。callやbindを使ってthisを明示的にバインドする修正を試みるも、エラーは解消せず。- 最終的に
DisqusCommentsを完全に削除してもIllegal invocationエラーが続くことから、RichTextRendererのdangerouslySetInnerHTMLが原因である可能性が高いと再確認。
最終的な解決策(暫定)
eval エラーと Illegal invocation エラーは、Cloudflare PagesのWorkers環境と dangerouslySetInnerHTML の相性問題、またはContentfulのリッチテキスト内の特定のコンテンツに起因する可能性が高いと判断しました。
RichTextRendererのdangerouslySetInnerHTMLを再度無効化: ブログコンテンツは表示されなくなりますが、サイト自体はエラーなく表示される状態に戻しました。- これにより、
evalエラーとIllegal invocationエラーは解消されました。
まとめ
今回のデバッグは、Gitの履歴操作から始まり、Next.jsのビルドシステム、TypeScriptの型システム、そしてCloudflare Pagesの特殊なランタイム環境まで、多岐にわたる知識と忍耐が試されるものでした。
- Git:
node_modulesは必ず.gitignoreに。履歴の書き換えはgit filter-branchで慎重に。 - Next.js: 型エラーは丁寧に潰す。
Imageコンポーネントのpriorityなど、警告も無視しない。 - Cloudflare Pages:
- サブディレクトリ構成の場合、ルートディレクトリ設定が必須。
- Next.jsの動的機能には
export const runtime = 'edge';とnodejs_compatフラグが必須。 dangerouslySetInnerHTMLや外部スクリプト(AdSense, Disqusなど)は、Cloudflare Workers環境ではevalやIllegal invocationエラーの原因になりやすい。
最終的に、ブログコンテンツの表示は一時的に無効化されましたが、サイト全体がエラーなく表示される状態に戻すことができました。今後は、Contentfulのリッチテキストのレンダリング方法を根本的に見直すか、CSPの緩和(非推奨)を検討する必要があります。