Next.js 13は新たなRailsとなるか？+ Supabase x Vercelによる爆速フルスタックWeb開発【個人開発】


# tl; dr
- Next.js 13 でフルスタックアプリを作った
- Supabase と Vercel はインフラを任せてしまおう
    - DB, 認証, デプロイをボタンポチポチで完結
    - Supabase, Next.js用の helper ライブラリ が すっっごい便利
- Next.js (RSC)は 少し昔の Rails になる
    - フロントからバックエンドまでこれ一個で完結する 

# 作ったもの

https://hashlog.vercel.app/

- ひとり用のSlack, Twitterのように、作業ログを時系列に記録できるアプリが欲しかったので作った。
- slackで分報 xx_times をやってる人におすすめ。 
- マークダウン記法に対応, `code`やリストでメモれる。
- ハッシュタグで関心ごとで分離
- Google アカウントでログイン
- 投稿前に、1つ以上タグを作る必要があります。(TODO fix)
![top.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83242/a57f0e6a-3ca2-0a14-dfdd-b0ef02a4d071.png)
![app.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83242/b256aaf1-0f08-37a1-ffad-212e34d5e1d9.png)



### ソースコード
- コード公開します
- リファクタリングのアドバイスなどがあればぜひissue投げて欲しいです。アプリ使ってみた報告でも！

https://github.com/shuent/hashlog


### 主なstack

- Next.js 13
    - App directory
- useSWR
    - data fetch & cache for client component
- tailwind css
- react-markdown
- typescript
- supabase: DB, 認証, 認可(RLS)
- vercel: deploy


## 開発のポイント

### Next.js
#### ディレクトリ管理
今回切り分ける軸は,DBモデル とpathの２つがあった。画面に関するものは,pathを基点にcomponentsを分けた。データ操作に近いものに関しては、モデルごとに分けていいかも。
```
src
├── actions
│   ├── hashtagActions.ts
│   └── postActions.ts
├── app
│   ├── (index)
│   │   ├── components
│   │   │   ├── Landing.tsx
│   │   │   └── screenTop.webp
│   │   └── page.tsx
│   ├── api
│   │   └── posts
│   │       └── route.ts
│   ├── auth
│   │   ├── callback
│   │   │   └── route.ts
│   │   └── logout
│   │       └── route.ts
│   ├── favicon.ico
│   ├── layout.tsx
│   └── logs
│       ├── components
│       │   ├── HashTags.tsx
│       │   ├── PostContainer.tsx
│       │   ├── PostForm.tsx
│       │   └── PostList.tsx
│       └── page.tsx
├── db.ts
├── middleware.ts
└── styles
    ├── gfm.css
    └── globals.css
```


#### App Directory

- Next.js 13 App Directory の Server Componentでは, `await`でデータフェッチ後に, 静的なページレンダリングを行うことができる。
```page.jsx
const ShowPage = () => {
  const data = await fetchData();
  return <>{data}</>;
};
```

- Client Component (昔からのブラウザランタイムで動くコンポーネント) を使う際は `'use client'`と明示する。
- 公式Docが分かりやすいので一通り仕組みを理解する。

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

#### Server Actions
- jsを使わないフォーム送信ができる
- actionをコンポーネントから呼び出すと, 自動でAPIエンドポイントを作り, `formData`を受け取る処理してくれる。
    - 必要に応じて actionの中でデータ再検証(revalidate)ができる。
        - 利用例: 新データ作成後に、データ一覧の更新を反映する
- `Experimental`ではあるが、[remix](https://remix.run/) でも同じような仕組みを採用していたので、標準になるはず。

https://nextjs.org/docs/app/api-reference/functions/server-actions

### Supabase
#### ログイン

supabase`signInWith`をクライアントで認証, callbackでcookieでsession保存。
ログイン判定, 認可には, サーバー側でセッションを取得, 全てライブラリに任せられる。
このページをよく読む。

https://supabase.com/docs/guides/auth/auth-helpers/nextjs

#### Supabase ライブラリの注意点
Next.js で supabase ライブラリを使う場合, 以下の２つインストールすることになるが, 
```shell
npm install @supabase/auth-helpers-nextjs @supabase/supabase-js
```
`supabase-js`は直接importして使わないこと。認証情報を引き継げず、RLS Policyを適切に設定したのにデータが見れなくて困った。[以下の方法](https://supabase.com/docs/reference/javascript/initializing)で読み込んではいけない。

```jsx
// auth-helpers-nextjsがある場合このコードはダメ
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('https://my-custom-domain.com', 'public-anon-key')
```

その代わりに`auth-helpers-nextjs`から Supabase Clientを作成する。以下のenvを宣言しておけば、勝手にenv読み込んでくれる。
```env.local
NEXT_PUBLIC_SUPABASE_URL=your-supabase-url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-supabase-anon-key
```

Supabase clientを作るには、[5種類の方法](https://supabase.com/docs/guides/auth/auth-helpers/nextjs#creating-a-supabase-client)があるので、それぞれ読み込むモジュールの中で最適なものを選ぶ。
>   Client Components — `createClientComponentClient` in Client Components
    Server Components — `createServerComponentClient` in Server Components
    Server Actions — `createServerActionClient` in Server Actions
    Route Handlers — `createRouteHandlerClient` in Route Handlers
    Middleware — `createMiddlewareClient` in Middleware

#### DB
Supabase管理画面内でポチポチ設定できる。認証設定も同様。[ローカル環境](https://supabase.com/docs/guides/cli/local-development)も作れる。初期は全て管理画面でテーブルを作り、リリース後は、MigrationでDBのスキーマ管理をしていくのが良い。Postgresなので、アプリが大きくなったらGCP,AWSマネージドSQLなどに移行、という戦略も取れる。

#### RLS

Row Level Security (RLS)Policyを設定すれば、Supabase DB側で認可を管理できる。ユーザーが、本人のデータのみを閲覧、編集可能にできる。アプリケーションコードで制御する必要がない。
こちらも管理画面ポチポチで設定できる。

https://supabase.com/docs/guides/database/postgres/row-level-security

#### useSWR 無限スクロール
無限スクロールを実装するには、動的にデータを取得する必要があった。Client Component でのデータフェッチにはuseSWRを使った。`useSWRInfinite`で簡単にデータ管理とページネーションが実現できる。

https://swr.vercel.app/ja/docs/pagination


#### vercel supabase 連携

vercel から supabase を連携することで、supabaseの環境変数を取ってきてくれる。Vercel画面内で環境変数を設定する必要がない。

真にgithubのrepositoryを選ぶだけで、デプロイできるようになった！

https://vercel.com/integrations/supabase

### その他 問題解決したこと
- supabase 本番とローカルで, google ログインした時の redirect 先 が一緒になってしまう問題 
    - https://github.com/supabase/supabase/issues/1895#issuecomment-864503163
    - siteUrl をvercel, local に redirectToと同じURLを入れて完了。
- `*/page.ts`で`cookies`を読み込もうとすると, 本番サーバーbuild時にエラーが。
    - https://github.com/vercel/next.js/issues/49373
    - `export const dynamic = 'force-dynamic'`を設定する必要がある。

## Next.jsは次のRailsになるのか

少し昔は Rails のerb と少しのajaxで画面作成は完結していた。Webアプリがリッチ化していくなかで、サーバーがAPI化, フロントがSPA と分離された。フロントでの状態管理やjwt認証などやることが増えた。SSRやMPAへのゆり戻しに。

今の JS Fullstack FW like Next.js, remix, は リッチなUI表現、UIの書き心地はそのままに、エンジニアが考えることを少なくする。(reinvented php とも言われている。)　

デプロイもボタン一発でできるPaaSがある。インフラはプロに任せられる。すると、よりビジネスロジック, UIUXに集中できる。

RailsチュートリアルをやればWebアプリを作れた時代に戻れるのかもしれない。




### 関連記事
https://zenn.dev/msy/articles/f13ac46a1d3f8e#%E3%81%BE%E3%81%A8%E3%82%81


## おわり
業務委託でのお仕事募集中です！フロント, バックエンド, GCPできます。