小中規模 Next.js Application で利用する技術選定

小〜中規模の Next Application を開発することになった場合に選択する技術、ライブラリ等について個人的に整理をしたのでメモとして残しておきます。

# 作成する Application の前提条件

- 画面数が1~10ページ程度で、画面間で共通のモデルを利用したい
- Next.js Application からバックエンドのシステムに対して API 呼び出しがある
- 入力項目が多いので途中で離脱しても状態を保持したい
    - ユーザーに紐づく入力情報をバックエンドに一時保存する仕組みが必要
    - 入力情報をフロント側では一元管理したい
- 入力フォームの要素はある程度パターン化されている
    - ボタンやテーブル表示などは component に切り出せる
    - トンマナ, fontサイズ等の変数は共通化したい

# 事前に必要な知識

- Next.js
  - チュートリアルをとおして一通りの基本機能を抑えておく
     - [https://qiita.com/thesugar/items/01896c1faa8241e6b1bc]
  - SPA or SSR ?
     - SEO 的にSPAを避けたい場合以外は SSR は不要
     - dynamic routing を使って体験的に価値がありそうなページがなければ、SSRは不要
- React.js
    - React Hooks とは何かを理解している
        - https://ja.reactjs.org/docs/hooks-intro.html
        - https://ja.reactjs.org/docs/hooks-reference.html
    - Redux とは何かを理解している
    - Hooks + Redux の使い方を理解している
        - https://react-redux.js.org/api/hooks
- CSS
    - TailWind CSS の使い方 

# Next.js

## Application の実行環境

- AWS Amplify
    - CI/CD環境の構築, 環境毎のURLを発行したりが容易にできる
    - AWS のリソース管理をしないといけないのでハードルが少し高い
    - ただし他の AWSリソースとの連携がしやすくなる
    - コスト面は低いのでおすすめ
- Vercel
    - https://vercel.com/
    - CI/CD環境の構築, 環境毎のURLを発行したりが容易にできる
    - Integration が提供されていて簡単に利用できる
    - 個人利用であれば無料
    - チーム利用になると料金はやや高い
    - 開発フェーズでサクッとPull Request毎に動作環境作って確認したいという用途であれば、個人利用でもできるのでおすすめ

# React.js

## ディレクトリ構成

- 参考となるディレクトリ構成
   - https://github.com/vercel/next.js/tree/master/examples/blog-starter-typescript
   - @\types ディレクトリはライブラリの [型定義ファイルを自作したものを配置](https://qiita.com/Nossa/items/726cc3e67527e896ed1e#2-%E5%9E%8B%E5%AE%9A%E7%BE%A9%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB-dts-%E3%82%92%E8%87%AA%E4%BD%9C%E3%81%99%E3%82%8B) 
   - types ディレクトリは Application 固有のモデルの型定義
- [React開発のディレクトリ構造について考える](https://qiita.com/mineyuji/items/8fb9ec044ab55e10de79)

```shell
# ディレクトリ構成の例

app
　L assets # 画像やcssファイルを定義
　　　L favicon.ico
　　　L app.css
 L components # Pages内で呼び出す Component を定義
    L atom # 原子、これ以上分解できない単位の Componet を定義
      L Button.tsx
      L ListItem.tsx
    L molecules # 分子、原子がいくつか組み合わさって構成された Component を定義
      L Header.tsx 
      L Footer.tsx 
      L List.tsx
    L Todo.tsx
 L pages # Next.js のページファイル
 L hooks # カスタム hooks を定義
 L stores # store関連のファイルを定義
 L reository # API, 環境依存な外部リソースの呼び出し処理を定義
    L xxxApi.ts 
 L @types # 型定義ファイルを自作したものを配置
    L xxxx.d.ts
 L types # Application 固有のモデルの型定義
    L Todo.ts
```

### Component ディレクトリ内の構成

Application 内で扱う Component の数によってディレクトリの分解を検討する必要があります。
atomic design をベースに基本要素である atom(原子), molecules(分子) というディレクトリ単位だけも
小さなプロジェクトでもファイルを分けやすいので最初の時点で作成しておくとよさそうです。

最初の段階でディレクトリを分けすぎているとどこにどの粒度のcomponentを配置したらいいのか混乱してしまうので段階的に分ける

## Storeの扱い

扱う store の大きさによって Redux を採用しつつ、技術検証な色がある案件であれば Recoil の採用を検討するのが良いかと思います

- パターン1: React hooks + Reduxを利用する
    - https://react-redux.js.org/api/hooks
    - [https://github.com/vercel/next.js/tree/master/examples/with-redux](https://github.com/vercel/next.js/tree/master/examples/with-redux)
    - https://github.com/vercel/next.js/tree/master/examples/with-redux-saga
- パターン2: React Context を利用する
    - https://mizchi.dev/202005271609-react-app-context
    -  Redux を導入するほど 扱うモデルが複雑でなければ React Context を利用して store 管理をする
- パターン3: Recoil を利用する
    - [https://recoiljs.org/](https://recoiljs.org/)
    - [https://mizchi.dev/study-recoil](https://mizchi.dev/study-recoil)
    - [話題の「Recoil」を使ってTodoアプリ作ってみた with TypeScript] (https://qiita.com/serinuntius/items/3d6519988233d7ba643c)
    - まだ Experimental であるものの実用性はありそうだしreduxに比べて学習コストが低そうなので、技術検証を目的とした Application 開発であれば採用してもよさそう

## React Hooks の利用について

- カスタム Hooks を利用してビジネスロジックを Component から分離をする
    - https://qiita.com/teradonburi/items/fbffcd1b7474795904a8
    - https://qiita.com/sonatard/items/617f324228f75b9c802f

## CSS の扱い

- styled-jsx + PostCSS
    - Component 個別のStyle は styled-jsx で記述して共通のトンマナは cssファイルで利用する CSSフレームワークを拡張する等がよさそう
    - Pluginを活用してPostCSSを拡張して利用
        - postcss-custom-properties
        - postcss-netsted
    - https://github.com/vercel/styled-jsx
    - https://github.com/vercel/next.js/tree/master/examples/with-styled-jsx-plugins
- styled-components
    - styled-jsx と同様のことができるが、style毎に Component を作らないといけないので軽量ではないので採用はしない
    - https://qiita.com/jagaapple/items/7f74fc32c69f5b731159

### CSS フレームワーク

- tailwind css
    - [https://github.com/vercel/next.js/tree/master/examples/with-tailwindcss](https://github.com/vercel/next.js/tree/master/examples/with-tailwindcss)
    - 導入手順 - [最小手数で始めるTailwind CSS](https://tech.medpeer.co.jp/entry/better-tailwind-css)
    - ベースのスタイルの拡張方法 - [Adding Base Styles](https://tailwindcss.com/docs/adding-base-styles/)
    - className の記述が冗長になりがちな場合は @\apply を利用して style に展開する
        - https://tailwindcss.com/docs/extracting-components#extracting-css-components-with-apply
    - 拡張 class を `tailwind.config.js` でpluginとして追加できるが、メンテナンス性や記述しにくさが気になるので css ファイル内に記述したほうがよさそう
        - https://tailwindcss.com/docs/extracting-components#writing-a-component-plugin