株式会社microCMS
⛅️

Cloudflare PagesでNext.js App Routerを使ってみる

2023/05/17に公開5

はじめに

Cloudflare Developer Week 2023にて数々の魅力的な発表がある中、Cloudflare PagesでNext.jsを利用するためのパッケージ@cloudflare/next-on-pagesv1.0.0となりました。

https://github.com/cloudflare/next-on-pages

執筆時の最新版である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

https://blog.cloudflare.com/making-cloudflare-for-web/

Edgeランタイムの設定

Cloudflare PagesではビルドはNode.jsが利用されますが、ランタイムははEdge Runtimeとなるので、利用するpage.tsxroute.tsそれぞれにruntime設定を追記しておきます。

src/app/page.tsx など
export const runtime = 'edge';

https://nextjs.org/docs/app/building-your-application/rendering/edge-and-nodejs-runtimes

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のスターターページが表示されるようになりました。

Next.js

Cloudflareのサービスを利用する

いったん最低限の動作は確認ができたところで、続けてCloudflareのサービスと連携も試してみます。
Next.js v13ではデータの取得に独自のcacherevalidateの機能を持っていますがCloudflare Pagesでは動作しません。

https://nextjs.org/docs/app/building-your-application/data-fetching/caching

とはいえCloudflareにはキャッシュ用途にも利用できるKey-Value型のストレージであるWorkers KVがあります。ここではKVの動作を試しておきます。

Workers KVを作成する

Workers > KV > 名前空間を作成する」を選択して新規にKVを作成します。

KVの作成

PagesとKVを紐付ける

PagesでKVを利用するにはバインディング(紐付け)が必要になります。再度Pagesの設定画面から作成したKVのバインディングを設定します。

Pagesのプロジェクトから、「設定 > Functions > KV 名前空間のバインディング」からKVを追加して保存します。(その他のサービスを利用する場合も都度バインディングの必要があります)

KV 名前空間のバインディング

KVにテスト用の値を追加

KVとの連携をテストするためにテスト用の値を追加しておきます。

key-valueの追加

KVの値をページで取得

さきほど登録したKVの値をページで取得、表示するためにsrc/app/page.tsxを書き換えます。あわせて@cloudflare/workers-typesもインストールしておきます。

npm install -D @cloudflare/workers-types
src/app/page.tsx
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

https://github.com/cloudflare/next-on-pages/issues/240

おわりに

駆け足にてCloudflare PagesでのNext.js(App Router)の動作を確認してみました。Next.jsの進化は早いので@cloudflare/next-on-pagesが都度どの程度までサポートしてくれるかにも依存してしまいますがCloudflare PagesでもNext.jsを利用することができそうです。プロダクションレベルでの利用を想定すると、決して楽な運用とはならないかもしれませんが、みなさんも挑戦してみてはいかがでしょうか:)

GitHubで編集を提案
株式会社microCMS
株式会社microCMS

Discussion

Yusuke HakamayaYusuke Hakamaya

とてもスムーズに Vercel から移行できました、ありがとうございます!1点、 next/image の最適化が一筋縄で使えない問題はどうクリアしましたか?カスタムローダーを自分で設定する方法は Cloudflare Image Optimization を利用するために $20/month の Pro プランが必要です。このため、今は泣く泣く <Image unoptimized={true} .../> にしています。他に試された方法がもしあれば、ご教示ください!

https://developers.cloudflare.com/images/image-resizing/integration-with-frameworks/

Hi MORISHIGEHi MORISHIGE

コメントありがとうございます!
確かにCloudflare Image Optimizationを利用するにはProプランが必須になりますよね。。

自分はある程度はあきらめて、最適化した画像を手元で用意しておく。
また、ヘッドレスCMSから配信するコンテンツは画像APIやimigixなどのAPIを利用することである程度容量を制御するようにしています。
https://document.microcms.io/image-api/introduction
https://imgix.com/

Cloudlfare Imagesから配信することでnext/imageでの最適化せずに配信することもできるのですが、こちらはこちらで$5/月かかってしまいます。(画像も別途アップロードが必要)
https://zenn.dev/kameoncloud/articles/7db419dbedc59d

ただどれもVercelでnext/imageを利用する場合の手軽さとはほど遠いものにはなってしまいますが。。
ご参考までに🙏

Yusuke HakamayaYusuke Hakamaya

やはりそうですよね。自分の知らないお手軽な方法がなさそうと分かったのも大きな前進です、ありがとうございます 🫡