Cloudflare PagesでNext.js App Routerを使ってみる
はじめに
Cloudflare Developer Week 2023にて数々の魅力的な発表がある中、Cloudflare PagesでNext.jsを利用するためのパッケージ@cloudflare/next-on-pages
がv1.0.0
となりました。
執筆時の最新版であるv13.4.2のApp Routerにも対応しているということで早速試してみました。
なお、現時点でサポートされている機能については@cloudflare/next-on-pages
のドキュメントにもまとまめられています。
検証環境
- Next.js v13.4.2
- @cloudflare/next-on-pages 1.0.0
試してみる
@cloudflare/next-on-pages
を使ってCloudflare Pagesにデプロイしてみます。
Next.jsのセットアップ
まずはNext.jsの環境を用意します。
npx create-next-app@latest my-next-app
cd my-next-app
Edgeランタイムの設定
Cloudflare PagesではビルドはNode.jsが利用されますが、ランタイムははEdge Runtimeとなるので、利用するpage.tsx
やroute.ts
それぞれにruntime設定を追記しておきます。
export const runtime = 'edge';
Cloudflare Pagesへデプロイ
@cloudflare/next-on-pages
をインストールします。
npm install -D @cloudflare/next-on-pages
GitHubリポジトリとの連携
今回はPagesへのデプロイにGitHubを利用します。
git init
git add .
git commit -m 'initial commit'
git remote add origin your-repository // 自分のリポジトリを入力
git push -u origin main
そしてCloudflare Dashboardにログイン後、「Pages > プロジェクトを作成 > Gitに接続」を選択して先ほど作成したリポジトリと連携します。
続けて、ビルド設定ではフレームワークとしてNext.jsを選択し、環境変数にNODE_VERSION
として16
以上のバージョンを指定する必要があります。
これでビルド、デプロイが走りますが一度目は失敗しています:)
Node.jsに依存するAPIが必要となるため、ビルド時に互換性フラグnodejs_compat
が必要なためです。
仕切り直して、Pagesのプロジェクトから、「設定 > Functions > 互換性フラグ」にてnodejs_compat
を追加して保存します。
失敗したデプロイを選択して「デプロイの再試行」を押下し再デプロイします。
これでNext.jsのスターターページが表示されるようになりました。
Cloudflareのサービスを利用する
いったん最低限の動作は確認ができたところで、続けてCloudflareのサービスと連携も試してみます。
Next.js v13ではデータの取得に独自のcache
、revalidate
の機能を持っていますがCloudflare Pagesでは動作しません。
とはいえCloudflareにはキャッシュ用途にも利用できるKey-Value型のストレージであるWorkers KVがあります。ここではKVの動作を試しておきます。
Workers KVを作成する
「Workers > KV > 名前空間を作成する」を選択して新規にKVを作成します。
PagesとKVを紐付ける
PagesでKVを利用するにはバインディング(紐付け)が必要になります。再度Pagesの設定画面から作成したKVのバインディングを設定します。
Pagesのプロジェクトから、「設定 > Functions > KV 名前空間のバインディング」からKVを追加して保存します。(その他のサービスを利用する場合も都度バインディングの必要があります)
KVにテスト用の値を追加
KVとの連携をテストするためにテスト用の値を追加しておきます。
KVの値をページで取得
さきほど登録したKVの値をページで取得、表示するためにsrc/app/page.tsx
を書き換えます。あわせて@cloudflare/workers-types
もインストールしておきます。
npm install -D @cloudflare/workers-types
import { KVNamespace } from "@cloudflare/workers-types";
export const runtime = "edge";
const getPlatform = async () => {
const { MY_KV_STORE } = process.env as unknown as {
MY_KV_STORE: KVNamespace;
};
const platform = await MY_KV_STORE.get("platform", "text");
return platform;
};
export default async function Home() {
const platform = await getPlatform();
return (
<main>
<p className="p-8">{platform}</p>
</main>
);
}
書き換えたところでデプロイして早速確認してみます。
KVに登録した値が表示されることが確認できました。ダッシュボードから値を変更すると表示も切り替わることも確認できるはずです。
補足
ローカル環境での開発では下記2つのコマンドを併用する必要がありますが、現時点では--watch
モードにビルドがループするバグがあるようです。すでにPRは出ているようなので少し待つ必要がありそう。
npx @cloudflare/next-on-pages --watch
npx wrangler pages dev .vercel/output/static --compatibility-flag=nodejs_compat
おわりに
駆け足にてCloudflare PagesでのNext.js(App Router)の動作を確認してみました。Next.jsの進化は早いので@cloudflare/next-on-pages
が都度どの程度までサポートしてくれるかにも依存してしまいますがCloudflare PagesでもNext.jsを利用することができそうです。プロダクションレベルでの利用を想定すると、決して楽な運用とはならないかもしれませんが、みなさんも挑戦してみてはいかがでしょうか:)
Discussion
とてもスムーズに Vercel から移行できました、ありがとうございます!1点、
next/image
の最適化が一筋縄で使えない問題はどうクリアしましたか?カスタムローダーを自分で設定する方法は Cloudflare Image Optimization を利用するために $20/month の Pro プランが必要です。このため、今は泣く泣く<Image unoptimized={true} .../>
にしています。他に試された方法がもしあれば、ご教示ください!コメントありがとうございます!
確かにCloudflare Image Optimizationを利用するにはProプランが必須になりますよね。。
自分はある程度はあきらめて、最適化した画像を手元で用意しておく。
また、ヘッドレスCMSから配信するコンテンツは画像APIやimigixなどのAPIを利用することである程度容量を制御するようにしています。
Cloudlfare Imagesから配信することで
next/image
での最適化せずに配信することもできるのですが、こちらはこちらで$5/月かかってしまいます。(画像も別途アップロードが必要)ただどれもVercelで
next/image
を利用する場合の手軽さとはほど遠いものにはなってしまいますが。。ご参考までに🙏
やはりそうですよね。自分の知らないお手軽な方法がなさそうと分かったのも大きな前進です、ありがとうございます 🫡
【参考までに】
pnpmを使っている場合、以下をビルドコマンドに設定しないと、ビルドが失敗してしまうようです。
https://github.com/cloudflare/next-on-pages/issues/544#issuecomment-1813349018 より
なるほどpnpmで利用したことなかったです。
情報ありがとうございます!