【Nextjs】Cloudflare Pagesにデプロイしようとしたら超苦労したので解決策を記録する

2024/01/03に公開
2

まえがき

記事の内容

Cloudflare PagesにデプロイしようとしたらPrismaが元凶で超苦労したので記事にします。
もう少し詳しく言うとCloudflare Pagesにデプロイするために必要なEdge runtimeをPrismaで使うためには設定が必要だったことです。
これからはメインのデプロイ先をCloudflare Pagesにしようと思っているので、今後の自分に対して道標を残しておきます。

結論

結局、PrismaのドキュメントにあるDeploy to Cloudflare Workersの通りすれば、あっさり解決しました。

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

ただ、1から10まですべて同じようにするのではなく、自分の環境に合わせて読み替えて進めていきます。

ブログアプリを開発中

今、Markdownで投稿できるブログアプリを開発しています。
技術スタックはNext.js、TypeScript、Prisma、Supabaseです。
年末からどう (パクる) 開発するのかリサーチし始めて、年末年始休みのうちにデプロイすることを目標に開発してきました。
開発は苦労しながらもある程度、形になってきました。

デプロイから始めるアプリ開発

そんな開発している中、以下の記事を見つけて読んでみました。

https://qiita.com/squid-cat/items/e6bb159a3c2b30e3405f

確かに、最終目標はデプロイなので先にやっておくことが大事だなと納得しました。
また私が思ったのは、いざデプロイができなくなった時に開発のどの時点で何が原因なのかはっきりすることです。
実はこれまで、開発はできたのにデプロイができないなんてことが日常茶飯事でした。
私のアプリの9割9分はデプロイできていません。
だったら、先にデプロイしておけばといいじゃんとツッコミが入ると思います。

デプロイ先の選定

ただ、これまでデプロイ先の選定ができていませんでした。
Next.jsで開発してるのだったら、デプロイ先はVercelが1番無難なのは分かっています。
お試しで、以下のアプリをデプロイしています。

https://trade-next-prisma-test.vercel.app/

https://github.com/arafipro/trade-next-prisma-chart

しかし、商用利用するなら月20ドルが必要になります。
今回のブログアプリには広告を載せて小銭を稼ごうと思っているので、月20ドルも払っていたら毎月赤字です。
そこで前々から気になっていたCloudflare Pagesを思い切って利用することにしました。
Cloudflare Pagesは無料で公開できて、それも商用利用がOKだったことです。
私の前提条件にぴったりです。
それにNext.jsのデプロイの仕方もドキュメントがあるので余裕っしょ!!とたかを括っていました。

伏兵Prisma

遅ればせながら、Cloudflareにアカウントを作成してサクッとデプロイ・・・。
ところがどっこい!!
今回の元凶、伏兵Prismaが正体を表します。
なんとPrismaが影響してデプロイできないなんて!!
ここから、開発がストップしてデプロイに苦労することになります。

ドツボにハマり冷静さをなくす

リサーチした結果、いくつかの記事を見つけました。
記事通りに試してみました。
しかし、私の実力不足でまったく解決しません。
正直、ドツボにはまってうまくいかずに冷静さを失っていました。

見つけた記事を見つめ直す

いったん落ち着いて見つけた記事を見直しました。
完全丸パクリになってしまいますが、以下の記事の冒頭の結論に答えがありました。

https://zenn.dev/niwatoro/articles/62554e6e0e77f4

それがこの記事の冒頭の結論で話したDeploy to Cloudflare Workersでした。

プロジェクト名

ここから本題に入りますが、以下の複数のプロジェクトを作成します。

  • Subabase
  • Next.js
  • Prisma Accelerate

すべて、ひとつのアプリに必要なプロジェクトです。
ただプロジェクト名がバラバラだと分からなくなります。
そこで、今回の記事ではすべてのプロジェクト名をprisma-supabase-sampleで統一します。
ちなみにプロジェクト名は自由に決めていただいて結構です。

Supabaseの設定

まずはSupabaseのデータベースの設定を行います。
この設定でPrismaの設定で必要な情報を取得します。

プロジェクトの作成

プロジェクトの作成ページは以下の通りです。

プロジェクト名を入力

統一したプロジェクト名prisma-supabase-sampleを入力します。

Database Passwordを作成

パスワードは自動生成されたものを使用します。

Database Passwordをコピー

パスワードは後で必要なのでコピーして控えておきます。

RegionをNorthest Asia(Tokyo)を選択

Create new Projectを実行

プロジェクトの設定

DashBoardに移動して、プロジェクトprisma-supabase-sampleを選択

Project Settingsに移動

Databaseの項目を選択

Connection stringからURIを選択してコピー

URIは後で必要なのでコピーして控えておきます。

Prismaの設定

以下のPrismaのドキュメントを参考に進めていきます。

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

プロジェクトの作成(1. Set up your application)

コマンドを実行

C3(create-cloudflare-cli)を使ってプロジェクトを作成します。

npm create cloudflare@latest

プロジェクト名入力

In which directory do you want to create your application?と聞かれます。
統一したプロジェクト名prisma-supabase-sampleを入力します。

オプションを選択

What type of application do you want to create?と聞かれます。
ドキュメントでは"Hello World" Workerを選択するように指示されていますが、
ここではNext.jsのアプリを作成するのでWebsite or web appを選択します。

フレームワークを選択

Which development framework do you want to use?と聞かれます。
Next(Next.js)を選択します。
その後はデフォルトのまま選択します。

Would you like to use TypeScript? › Yes
Would you like to use ESLint? › Yes
Would you like to use Tailwind CSS? › Yes
Would you like to use `src/` directory? › No
Would you like to use App Router? (recommended) › Yes
Would you like to customize the default import alias (@/\*)? › No

ESLint Pluginの導入

Do you want to use the next-on-pages eslint-plugin?と聞かれます。
そのままyesを選択します。

アプリケーションをデプロイ

Do you want to deploy your application?と聞かれます。
そのままyesを選択します。

Prismaのセットアップ
(2. Set up Prisma)

https://www.prisma.io/docs/orm/prisma-client/deployment/edge/deploy-to-cloudflare-workers#2-set-up-prisma

ライブラリのインストール

npm install --save-dev prisma

Prismaの初期化

npx prisma init

初期化すると以下のファイルが自動で作成されます。

  • .env
  • prisma/schema.prisma

.envの設定

.env
# Environment variables declared in this file are automatically made available to Prisma.
# See the documentation for more detail: https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema

# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB and CockroachDB.
# See the documentation for all the connection string options: https://pris.ly/d/connection-strings

DATABASE_URL="postgresql://johndoe:randompassword@localhost:5432/mydb?schema=public"

上記のように、ファイル.envが作成されます。
不要なコメントは削除しておきます。

.env
- DATABASE_URL="postgresql://johndoe:randompassword@localhost:5432/mydb?schema=public"
+ DATABASE_URL="postgresql://postgres:[YOUR-PASSWORD]@db.apkdlvkzcbxzhrqbqiti.supabase.co:5432/postgres"

DATABASE_URLにSupabaseの設定で取得したURIをコピペします。
またデータベースのパスワードを[YOUR-PASSWORD]と置き換えます。

schema.prisma

PrismaスキーマにPostモデルを追加

prisma/schema.prisma
generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider  = "postgresql"
  url       = env("DATABASE_URL")
}

model Post {
  id      Int    @id @default(autoincrement())
  title   String
  content String
}

データベーススキーマを更新
(3. Update your database schema)

https://www.prisma.io/docs/orm/prisma-client/deployment/edge/deploy-to-cloudflare-workers#3-update-your-database-schema

npx prisma migrate dev --name init

Prisma Data PlatformでAccelerateを有効にする
(4. Enable Accelerate in the Prisma Data Platform)

https://www.prisma.io/docs/orm/prisma-client/deployment/edge/deploy-to-cloudflare-workers#4-enable-accelerate-in-the-prisma-data-platform

Prisma Data Platformアカウントにサインアップ

https://console.prisma.io/

GitHubアカウントでサインアップします。

プロジェクトの作成

New Projectを選択します。

統一したプロジェクト名prisma-supabase-sampleを入力します。
入力したらCreate Projectを実行します。

Accelerateの設定に移動

Database connection string

Supabaseのプロジェクト設定で取得したURIを貼り付けます。
また、[YOUR-PASSWORD]の部分はSupabaseのデータベースのパスワードに置き換えます。

Region

Asia Pacific (Tokyo)を選択を選択します。

Enable Acclerate

Generate API key

API KEYをコピー

API KEYをコピーしておきます。

Prisma Clientのインスタンスを作成

最初に作成したNext.jsのプロジェクト内にprisma.tsを作成します。

まずは、指示通りにコピペします。

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

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

しかし、今回はPrismaClientをインポート元を以下のように変更します。
なぜなら、Cloudflare PagesにデプロイするにはEdge runtimeが必要だからです。

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

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

またプロジェクト内で参照できるようにexportconst prismaの前に付け加えておきます。

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

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

プロジェクトでAccelerate接続文字列を構成
(5. Configure the Accelerate connection string in your project)

https://www.prisma.io/docs/orm/prisma-client/deployment/edge/deploy-to-cloudflare-workers#5-configure-the-accelerate-connection-string-in-your-project

.envファイルを変更

コピーしておいたAPI KEYを.envファイルに追加します。
そして元々あったDATABASE_URLDIRECT_URLに変更します。

.env
# 新しいAPI KEY
+ DATABASE_URL="prisma://accelerate.prisma-data.net/?api_key=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhcGlfa2V5IjoMtYzUzMTY0NTJiNygtYjU4Njk0OGVhMGE0IiwW50X2lkIjoiNWX3NlY3JldCI6IjRlZGViZE0YtNDI3Zi0MS00NzZmLWI4ND04NGE2NhYmYMzE0MmVmODc0YzRiMzgxZWNmODc0MWViMWMwMzdkMTmMDA1MjE4M2ViMmY5ZDY4MmIIsImludGVybmFsWidGVuYE3LTA5OGEwLTZhNT2NWZiOTdmJjZTRjNjhlYyJ9.JMe-4ZZfbIi_VY9eqNay-_rdMEWFKYAcFNhYPGzsgXQ"

# 元々あった`DATABASE_URL`は`DIRECT_URL`に変更
- DATABASE_URL="postgresql://postgres:[YOUR-PASSWORD]@db.apkdlvkzcbxzhrqbqiti.supabase.co:5432/postgres"
+ DIRECT_URL="postgresql://postgres:[YOUR-PASSWORD]@db.apkdlvkzcbxzhrqbqiti.supabase.co:5432/postgres"

prisma/schema.prismaファイルを変更

.envファイルを変更に合わせてdirectUrlプロパティをdatasourceに追加します。

prisma/schema.prisma
  generator client {
    provider = "prisma-client-js"
  }
  
  datasource db {
    provider  = "postgresql"
    url       = env("DATABASE_URL")
+   directUrl = env("DIRECT_URL")
  }
  
  model Post {
    id      Int    @id @default(autoincrement())
    title   String
    content String
  }

Prisma Accelerate拡張機能をインストール

以下のコマンドを実行して、Accelerate Prisma Clientをインストールします。

npm install @prisma/extension-accelerate

実行すると先ほどのエラーが解消されます。

Prisma Clientの生成(6. Generate a Prisma Client)

Accelerate用Prismaクライアントの作成

以下のコマンドを実行して、Accelerate用Prismaクライアントの作成します。

npx prisma generate --no-engine

環境変数の設定

以上でデプロイに必要な設定が終わりました。
これでデプロイ時にエラーが発生することはなくなったはずです。

ただCloudflare Pagesにデプロイした場合、.envで設定した環境変数は読み込まれません。
そこでCloudflareのダッシュボードから環境変数の設定をする必要があります。
まずは左のサイドバーのWorkers & Pagesのドロップダウンメニュから概要を選択します。
概要のプロジェクトの一覧からprisma-supabase-sampleを選択します。
設定を選択した後、環境変数を選択します。
プロダクションの環境変数に.envの2つの変数を追加します。

  • DATABASE_URL
  • DIRECT_URL

あとがき

長い工程で大変でしたが、おつかれさまでした。
今後の自分のために記録しておくのが目的ですが、皆さんの手助けになれば幸いです。

https://github.com/arafipro/prisma-supabase-sample

youtubeチャンネル「typescriptでフルスタックエンジニアになる」を運営しています。

https://www.youtube.com/channel/UCqmIGhDsE5y-fmjtp8SnblQ/

Cloudflare WorkersにAPIを作成したり、Cloudflare Pagesにデプロイする前提でフォームの作り方や認証機能の使い方を動画にしています。
ぜひ、ご覧ください。

GitHubで編集を提案

Discussion