土曜日, 7月 26, 2025
土曜日, 7月 26, 2025
- Advertisment -
ホームニューステックニュースNext.js & Cloudflareざんまいは、simpleだけどeasyじゃない。けど、まぁ、いいわ。

Next.js & Cloudflareざんまいは、simpleだけどeasyじゃない。けど、まぁ、いいわ。



どうせみんな、Cloudflareのことが好きなんでしょ。
私も大好き。
だってCloudflareってDBとかストレージとか色々あって、そんでもって無料枠が東京ドーム◯個分だもんね。
もうできるだけCloudflareに乗っかってアプリ作りたいわよね。
だから私、やってみたわ。
やってみた感想は、辛かったわ。。。
だけどその辛さを超えてしまえば、まぁ動くようになったしええか、って感じだわ。
何が辛くて、どうやって辛さを解消したかをシェアするわね。

Cloudflareざんまいの構成

  • Cloudflare D1
  • Cloudflare R2
  • Cloudflare Workers
  • Cloudflare Workers KV
  • Cloudflare Images
  • Cloudflare Registrar
  • Next.js
  • Auth.js
  • Drizzle ORM

すんごいCloudflareでまとまっててsimpleな構成よね。
この構成でローカルで開発してて全てがうまくいって、「アタシ最強!」ってなってたわ。
だけどCloudflare Workersにデプロイしたら全然うまくいかなくなって、「アタシ最弱…」ってなったわ。
このとき思ったわ。
「simpleだけどeasyじゃない」って。

非easyポイント

Next.jsとCloudflareの組み合わせだから沼った内容とか、Next.js & Vercelの感覚で使ったら沼った内容を取り上げるわ。

  • 最新のNext.jsが使えない
  • Prismaが使えない
  • サインアウトができない
  • generateStaticParamsが使えない
  • R2にアップロードできない

最新のNext.jsが使えない

これを書いている2025年7月下旬時点でNext.jsはv15.4がリリースされてるけど、v15.4はCloudflare Workersでは使えないわ。
Cloudflare Workersにデプロイは成功するんだけど、アクセスしてみるとたしか500エラーの画面になったわ。
ログには以下が出てたわ。

Failed to prepare server Error: An error occurred while loading the instrumentation hook

解決策

Next.jsをv15.3にしたらエラーを解決できて、無事に動いたわ。
v15.4が使えない問題は、おいおい対応してもらえるかも。

https://github.com/opennextjs/opennextjs-cloudflare/issues/667#issuecomment-3078374140

ありがとがんば٩(๑•o•๑)و ファイト♡♡

Prismaが使えない

Drizzleを使う前にPrismaを使ってて、ローカルではめっちゃ元気に動いてたのよ。
でもCloudflare Workers上でDBにデータを保存しようとしたら、500エラーになったわ。
ログには、Error: [unenv] fs.readdir is not implemented yet!ってエラーが出てたわ。

解決策

「Drizzleオススメ」ってコメントを見かけたからPrismaをDrizzleに差し替えたら、Cloudflare Workers上でも元気よく動いてくれたわ。

https://github.com/opennextjs/opennextjs-cloudflare/issues/734#issuecomment-2981042635

ただ、Drizzleに差し替えた後に分かったんだけど、私がPrisma Clientの出力先を設定しちゃったのが、エラーの原因だったっぽいわ。
OpenNextのドキュメントに、「出力先を書かんでよろし」って書いてあるのを見つけたの。

https://opennext.js.org/cloudflare/howtos/db#schemaprisma

だからPrisma Clientの出力先を変えなくていいんだったら、Prismaを使えるわよたぶん。

サインアウトができない

Auth.jsって、サーバーサイド用とクライアント用のsignOutがあるじゃない?

import NextAuth from "next-auth";

export const { handlers, signIn, signOut, auth } = NextAuth({
...
import { signOut } from "next-auth/react";
...

この子たちCloudflare Workers上では、どっちを使ってもサインアウト状態にならなかったわ。
auth()の戻り値を使ってサインイン状態の判定をしてたんだけど、Cloudflare Workers上では以下の状態になってたわ。

  1. signOut実行
  2. auth()の戻り値がnullになってサインアウト状態になる
  3. ページをリロードするとサインイン状態になる

ブラウザのデベロッパーツールでCookieを確認したら、サインアウトしても__Secure-authjs.session-tokenが消えなかったから、サインイン状態に戻っちゃってたのね。

解決策

middlewareでCookieを削除するようにしたら、サインアウト状態になったわ。

https://github.com/nextauthjs/next-auth/issues/12909

上記のIssueに__Secure-authjs.session-tokenが消えなかったか理由が書いてあったわ。
サインアウトした際に2種のSet-Cookieが送信されてるみたいで、その2種を読む順番がCloudflare Workersと噛み合ってなかったみたい。
これはAuth.jsとCloudflare Workersの相性がよろしくなかったのね。
だからCloudflare Workersを使うのなら、Auth.js以外を使ってみるといいわ。
最近はBetter Authっていう子を、界隈でよく見かけるわね。

https://www.better-auth.com

generateStaticParamsが使えない

こういうの書くでしょ。

export async function generateStaticParams() {
  const { env } = getCloudflareContext()
  const db = drizzle(env.DB, { schema })
  ...

そしてビルドしたら、以下のエラーが出たわ。

ERROR: `getCloudflareContext` has been called in sync mode in either a static route or at the top level of a non-static one, both cases are not allowed but can be solved by either:
  - make sure that the call is not at the top level and that the route is not static
  - call `getCloudflareContext({async: true})` to use the `async` mode
  - avoid calling `getCloudflareContext` in the route

ちなみにsitemap.tsでもDBを使う状態でビルドしたら、同じエラーが起きたわ。

解決策

エラーメッセージに書かれてる、非同期モードを使うことで解決できたわ。

export async function generateStaticParams() {
  const { env } = await getCloudflareContext({ async: true })
  const db = drizzle(env.DB, { schema })
  ...

ただ、私drizzle関数の戻り値を返すユーティリティを各所で使っていたから、色々と書きなおすのがめんどくさかったわ。
最初から言ってくれればよかったのに。

R2にアップロードできない

以下のドキュメントに従って、ファイルのアップロード機能を実装したわ。

https://developers.cloudflare.com/r2/examples/aws/aws-sdk-js-v3/

そしてCloudflare Workers上でファイルをアップロードしたら、以下のエラーが出たわ。

Error: [unenv] fs.readFile is not implemented yet!

解決策

@aws-sdk/client-s3の代わりにaws4fetchを使うことで、Cloudflare Workers上でファイルをアップロードできるようになったわ。
@aws-sdk/client-s3が内部でfsを使ってるのかもね。
このエラーの原因が@aws-sdk/client-s3を使ってることなんだとしたら、Cloudflare Workersで機能しないライブラリをR2のドキュメントに載せるのはこれいかに、って感じだわ。

ひょっとしたら、simpleじゃない & easyじゃない

アプリを作るために異なる会社のサービスを組み合わせるのって、なんかsimpleじゃないでしょ。
対してCloudflareざんまいって、すごいsimpleよね。
Cloudflareのコンソールに行けば、大抵のことを設定したり確認できるし。
個人的には「なんかまとまってていい!」っていう、精神的な充足感を得られているわ。

とはいえ、実装の観点だとsimpleじゃない気がするわ。
私が沼でもがいた結果、以下の約束事を見つけられたわ。

  • Cloudflare Workers & Next.jsを使う場合、特定のバージョンを避ける
  • Next.js & Cloudflare D1 & Prismaを使う場合、Prisma Clientの出力先を変更しない
  • Cloudflare Workersを使う場合、内部でNode.jsの組み込みモジュールを使っていないライブラリを選定する
  • Cloudflare Workers & Auth.jsを使う場合、サインアウトに関する処理をmiddlewareに施す

こういう「コレをするなら、アレをしなければいけない」みたいな約束事があるような状態って、simpleとは言いにくいんじゃないかしら。
だって「Cloudflare WorkersでNext.js使えるよ!」って言われて、いざ手を出したら「あ、ただしバージョンは15.3にしなきゃ動かないよ」って言われたら、「えーなにそれ聞いてない」ってなるじゃないのさ。

加えて、こういう約束事が書かれている場所がGitHubのIssueであったり、ドキュメントだったりに点在しているところも、simpleではない印象だわ。
例えばPrisma Clientの出力先を変えると機能しなくなる旨は、OpenNextのドキュメントには書いてあるけど、Cloudflare D1とPrismaのドキュメントには書かれていないっぽいわ。

https://developers.cloudflare.com/d1/tutorials/d1-and-prisma-orm/#2-initialize-prisma-orm

https://www.prisma.io/docs/orm/overview/databases/cloudflare-d1

これに関してはNext.jsと組み合わせた場合の約束事だから、OpenNextのドキュメントにだけ書いてあるんでしょうけれども。

けど、まぁ、いいわ。

だって、エラーを解決できたもん。
エラーを解決できて、Cloudflareざんまいなsimpleな構成で、アプリを運用できているもん。
「エラー上等!ランニングコスト掛けたくない!」って人なら、Next.js & Cloudflareざんまいにする価値はあるわ。

ちなみにデプロイ先をCloudflare WorkersからVercelに変えれば、前述したeasyじゃないポイントはほぼ解消できると思うわ。
VercelはCloudflare Workersに比べて無料枠が小っちゃいし、無料プランだと商用利用ができないんだけど、そこを許容できるんだったらVercelを使うのもアリよ。



Source link

Views: 0

RELATED ARTICLES

返事を書く

あなたのコメントを入力してください。
ここにあなたの名前を入力してください

- Advertisment -