Open5

Cloudflare Pages + Next.js + Prisma + NextAuthのデプロイ

zerebomzerebom

https://www.prisma.io/docs/orm/prisma-client/deployment/edge/deploy-to-cloudflare#database-specific-considerations--examples

デプロイがむずかしかったのでメモする

モチベーション

  • 無料で個人開発アプリをデプロイしたい

なぜこの実装構成?

  • フロントエンドライブラリ: 会社で使われているので勉強したかった。フロントの知識があまりないので、ディレクトリ構造など、フレームワーク側で規定してくれるのは便利そう。
  • ホスティング: VercelのHobbyは広告貼れなかったりかなり厳しいので、無料枠が緩いCloudflare Pagesを使いたい
  • ORM: DBにはSupabaseを使っている. 生でクエリ書きたくないので評判のいいPrismaを採用
  • 認証: 認証の知識が殆ど無いので、少ない記述量で設定できるNextAuthを採用
zerebomzerebom

なぜむずかしいのか

https://authjs.dev/guides/edge-compatibility
に詳しく記載されている.

  • Cloudflare Pagesはedgeで動いている
    • node.jsに存在するが、edgeには存在しないメソッドが存在する
    • TCPソケットを使うPostgresなど、Webサーバーを前提した技術スタッツがそのままでは使えないことがある
  • なので、上記に対応したバージョンの技術スタッツを使う必要がある
  • Auth.jsだけなら大したことないが、ORMやDBを使うとなると工夫が必要

対策

Next.js側の対応

edgeで実行するページ(page.tsx, route.ts)に下記を追記する

export const runtime = 'edge';

Prismaの対策方法

https://www.prisma.io/docs/orm/prisma-client/deployment/edge/deploy-to-cloudflare

  • prisma data platformでProject作成
  • supabaseのDATABASE_URLを渡し、出てきたURLを.envに記載する
  • 最後に出てきた設定値をprisma.tsに記載

※ zennに書いてあるやり方。 https://www.prisma.io/docs/orm/prisma-client/deployment/edge/deploy-to-cloudflare#database-specific-considerations--examples には特に出てこないので、公式は別の方法を勧めてるのかな?(よくわかってない)

NextAuth

https://authjs.dev/guides/edge-compatibility#split-config
のSolutionの、Split Configを参照すれば良いはず。

edgeで動くように、スタンドアロンな設定値だけを持ったClientと、DBとかedgeで動かない設定値を遅延処理することで、上手く回避している?

最終的な設定

prisma.ts

import { PrismaClient } from '@prisma/client/edge'
import { withAccelerate } from '@prisma/extension-accelerate'


const prisma = new PrismaClient().$extends(withAccelerate())
export default prisma

schma.prisma

generator client {
  provider   = "prisma-client-js"
}

datasource db {
  provider  = "postgresql"
  url       = env("DATABASE_URL")
  directUrl = env("DIRECT_URL")
}
import NextAuth,{ DefaultSession } from 'next-auth'
import authConfig from "./auth.config"
import { PrismaAdapter } from "@auth/prisma-adapter"

import prisma from '@/lib/prisma'
declare module 'next-auth' {
  interface Session extends DefaultSession {
    user: {
      id: string
    } & DefaultSession['user']
  }
}

export const { handlers, auth, signIn, signOut } = NextAuth({
 adapter: PrismaAdapter(prisma),
  session: { strategy: "jwt" },
  ...authConfig,
  callbacks: {
    async session({ session, user }) {
      if (session.user) {
        session.user.id = user.id
      }
      return session
    },
  },
})

デバッグ方法

Pagesにデプロイしてからのログの計測

pnpm add wrangler --save-dev
pnpm wrangler pages deployment tail

デプロイがうまくいくか
Pagesのデプロイで行われているnpx vercel build をローカルで実行する

自分が詰まった箇所

https://github.com/prisma/prisma/issues/21428
PrismaClientValidationError: Invalid client engine type, please use libraryorbinary`が消えない
→ package.jsonのscripts "postinstall": "prisma generate --no-engine"の --no-engineが足りなかった

https://www.prisma.io/docs/orm/prisma-client/deployment/edge/deploy-to-cloudflare#postgresql-traditional
→ pgをinstallするとnode_module配下のfsライブラリを読み出してedgeで動かなくなるのでやってはいけない

zerebomzerebom

学び・反省

  • Next.jsもReactもPrismaもSupabaseもCloudflare PageもNextAuthもよくわかってない状態ですべて採用したので、問題を切り分けるのに時間がかかった
  • 新しめの技術はLLMに直接聞くより、ドキュメント + issueを読んだり、それをLLMに投げた方が早い
  • NextAuthのEdge Compatabilityのページはかなり前提から書かれていたので、これを読んでから、何が壊れているのか理解が早くなった
    • 公式が提供してる背景ありの読み物をちゃんと読むと早い
  • Cloudflare Page + NextAuth や Cloud flare Page + Prismaの構成のドキュメントは結構多いので、自分が採用しているツールの変数を減らした上でドキュメントを漁った方が早い