【Cloudflare Pages/D1】個人開発のためのローリスクなクラウドを探し求めてCloudflareに出会う【Next.js】

# はじめに

以前こんな記事を書いたのですが、

https://qiita.com/Hanull/items/f23f3211f115d87eac78

個人開発でWebサービスの作るのに
<strong>リスクを下げることの重要性</strong>を痛感したことがありました。

なので、また懲りずに新しいWebサービスを作ったのですが、
できるだけローリスクを心がけて開発した。

ここで心がけたローリスクっていうのは、
<strong>開発と運用にかかるコスト・学習コスト・保守コスト</strong>
をできるだけ低くすることで、
失敗しても受けるダメージを少なくするということです。

ローリスクのために色々考えていたら、
無料で使える枠が多くて、D1が正式にリリースされた 
Cloudflareが良さそうだったので、
その話を中心に書きたいと思います。

# 宣伝
ローリスクを意識しすぎるとその分クオリティが低くなってしまいそうですよね。
なので宣伝ついでに実物を見てもらえると幸いです。

https://oshitime.jp

前回に続きまた推し活系のWebサービスを作りました。
今回の<strong>推したいむ</strong>は推しと推しのイベントを登録して、
推しのスケジュールをファン同士で共有して、
その中から自分が参加するイベントをフォローするこで、
自分の推し活カレンダーがつくれるサービスです。

# 環境
構築環境とそれを選んだ理由

### Cloudflare Pages
フロントエンドサーバー
- 無料で無制限のサイト・無制限のリクエスト・無制限の帯域幅・500回のビルド/月
- 商用利用可能
- データベースも一緒に構築可能

### Cloudflare D1
データベースサーバー
- 5GBまで無料
- SQL

### Next.js
フロントエンドフレームワーク
- 使い慣れてる
- ネットに記事が多い
- ライブラリが豊富

### Tailwind CSS
CSSフレームワーク
- Cloudflare Pagesと相性がいい
- Next.jsと相性がいい
- CSSが苦手でも使える
- デザインが苦手でもそっれぽくなる

### shadcn/ui
CSSフレームワーク
- Tailwind CSSと相性がいい
- Next.jsと相性がいい
- デザインが苦手でもさらにそっれぽくできる

### Drizzle ORM
ORM
- Cloudflare D1との相性がいい

### Hono
バックエンドフレームワーク
- Drizzleと相性がいい



# つまずきポイント
Cloudflare Pages・D1はまだあまり日本語での記事が少なく、
つまずきポイントがいくつかあったので解説したいと思います。

## Next.js
Next.jsをNext.jsでビルドするにはランタイムをEdge Runtimeに設定します。
Firebase AuthなどEdge Runtimeに対応していないライブラリがあるので、
その辺の注意が必要です。

### Firebase Auth
Edge Runtime に対応していないため断念
next-firebase-auth-edgeを使えばいけるかもしれない？

https://github.com/awinogrodzki/next-firebase-auth-edge

Firebase Auth が使えなくてもGoogle認証するだけなので NextAuth を使用する

### NextAuth.jsはv5
NextAuth v4 は Edge Runtime に対応していないので
2024/2/14時点ではbetaをインストールしないとCloudflare pagesでビルドできない
```
$ npm install next-auth@beta
```


## Chakra UI
Cloudflare pages で Emotion に依存しているUIフレームワークは使えない
代わりに Tailwind CSS と shadcn/ui を使用


## 環境変数でAUTH_TRUST_HOST=true
clodflare Page でデプロイしたら
/api/auth/session が 500 Internal Sever Error でログインしようしても
Sever error と表示されてしまう
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2727171/70459ba1-0cf1-86fd-5fde-ff69291f301a.png)
環境変数に AUTH_TRUST_HOST=true を追記する必要がある

NEXTAUTH_URL="http://localhost:8788/api/auth"
でAPIからauth()呼び出すしてもnullにならなくなる

```wrangler.toml
[vars]
GOOGLE_CLIENT_ID=【hoge.apps.googleusercontent.com】
GOOGLE_CLIENT_SECRET=【GOOGLE_CLIENT_SECRET】
NEXTAUTH_SECRET=【Secret】
NEXTAUTH_URL="http://localhost:8788/api/auth"
AUTH_TRUST_HOST=true
```

## HonoからD1接続
まず cloudflare のページで D1 の設定をし、
HonoからD1を呼び出そうとしたらエラーが出ました。
``` api/[...route]/route.tsx
import { Hono } from "hono";
import { drizzle } from "drizzle-orm/d1";
import { users } from "../../../../schema";

export const runtime = "edge";

// This ensures c.env.DB is correctly typed
type Bindings = {
  DB: D1Database;
};

const app = new Hono<{ Bindings: Bindings }>().basePath("/api");

app.get("/user", async (c) => {
  const result = await drizzle(process.env.DB).select().from(users).all();
  return c.json(result);
});

export const GET = app.fetch;
export const POST = app.fetch;
```
で process.env.DB でenvにDBがないと怒られます。
なので process から Bindings に接続できるように
以下の追記をします。

```env.d.ts
declare global {
  namespace NodeJS {
    interface ProcessEnv {
      DB: D1Database;
    }
  }
}
```
このままだとローカルで試すとデータベースが空になってしまうので
以下を追記
``` wrangler.toml
[[ d1_databases ]]
binding = "DB" # i.e. available in your Worker on env.DB
database_name = "oshitime"
database_id = "10cc517a-17a4-4e13-9095-57babdd91e2e"
migrations_dir = "drizzle/migrations"
preview_database_id = "DB" # <-- 特にこれ注意
...
```
これ試しに実行して確認
```
$ npm run pages:preview   
```

# さいごに
Cloudflareは心配になるくらい無料で使用可能な枠がでかいです。
個人開発でその辺をネックに感じていた人は検討の余地大アリです。
あと[推したいむ](https://oshitime.jp)と[X(Twitter)アカウント](https://twitter.com/hanulldog)の方もよろしくお願いします。