Next.js を Cloudflare Pages にデプロイする with App Router, Terraform, モノレポ
前提
既存の Next.js v14 製アプリケーションを Cloudflare Pages にデプロイする。
アプリケーションはモノレポになっており、Next.js 製の Web だけをデプロイしたい。
今回は Git 統合でのデプロイは行わない。
環境
- Next.js v14.1.4
参考情報
runtime 指定
サーバーコンポーネントに export const runtime = 'edge';
を追記した。
なお、parallel routes を使っており、children にあたる page.tsx がなく layout.tsx しかないルートがあったが、これにも edge
指定をする必要があった。解決のために null
を返す page.tsx を置いた。
export const runtime = 'edge';
export default function Page() {
return null;
}
Cloudflare Pages の作成
アプリ側の準備は一旦終了。Terraform で Cloudflare Pages を作っていく。
なお、Cloudflare のプロジェクト作成、tfstate をリモート管理するなどの設定は済み。
sops で secrets.yaml に機密情報を暗号化して保存してある。
terraform {
required_version = "~> 1.8.0"
backend "gcs" {
bucket = "example-tfstate"
prefix = "services/example"
}
required_providers {
cloudflare = {
source = "cloudflare/cloudflare"
version = "~> 4.0"
}
sops = {
source = "carlpett/sops"
version = "~> 1.0"
}
}
}
provider "cloudflare" {}
provider "sops" {}
resource "cloudflare_pages_project" "default" {
account_id = data.sops_file.secrets.data["cloudflare.account_id"]
name = "example"
production_branch = "main"
}
data "sops_file" "secrets" {
source_file = "secrets.yaml"
}
export CLOUDFLARE_EMAIL=<YOUR_EMAIL>
export CLOUDFLARE_API_KEY=<YOUR_API_KEY>
terraform init
terraform plan
terraform apply
まだデプロイされていない Pages ができた。
ローカルでビルド
@cloudflare/next-on-pages の README を参考に進める。
npm install -D @cloudflare/next-on-pages
ローカルでビルドする。
npx @cloudflare/next-on-pages
ローカルでプレビュー
プレビュー用に localhost でアプリを立ち上げる。もろもろの動作を確認する。E2E テストが全て通ったので動作は大丈夫そう。
npx wrangler pages dev .vercel/output/static --compatibility-flag=nodejs_compat --port 3000
デプロイ
wrangler コマンドでデプロイする。
wrangler pages deploy .vercel/output/static
デプロイはできたが、ページを開くと Node.JS Compatibility Error
と表示された。Cloudflare Pages 側には Next.js 用の設定をまだ何もしていないので、Terraform に戻って必要な設定を足していく。
nodejs_compat
を足して terraform apply
した。
resource "cloudflare_pages_project" "default" {
account_id = data.sops_file.secrets.data["cloudflare.account_id"]
name = "example"
production_branch = "main"
deployment_configs {
production {
compatibility_flags = ["nodejs_compat"]
}
}
}
再度デプロイするとページが開いた。 🎉