個人的にたどり着いたディレクトリ構造

# はじめに

最近VueやReactを何度か触って得た知見を元に、個人的に良さげなディレクトリ構造を考えたいと思います

:::note warn
2023/02/18 追記
多くの方に見てもらえているようなので全体的にちゃんと書き直しました！
:::

# ディレクトリ構造

Next.js 13だと仮定します

```
src/
├── app
│   ├── globals.css
│   ├── head.tsx
│   ├── layout.tsx
│   └── page.tsx
├── components
│   ├── base
│   │   ├── atoms
│   │   └── molecules
│   ├── feature
│   │   └── hoge
│   │       ├── atoms
│   │       ├── molecules
│   │       ├── hooks
│   │       ├── hoge.constants.ts
│   │       └── hoge.types.ts
│   ├── functional
│   └── page
├── hooks
├── libs
├── pages
│   └── api
├── providers
├── stores
│   └── fuga
│       ├── atoms.ts
│       ├── operations.ts
│       ├── selectors.ts
│       └── types.ts
├── types
└── utils
```

## 基本

基本は以下の構成を参考にさせていただいています

https://tech-blog.rakus.co.jp/entry/20230208/frontend

https://qiita.com/misuken/items/19f9f603ab165e228fe1

https://zenn.dev/warabi/articles/2521222d57a71f

https://zenn.dev/yoshiko/articles/99f8047555f700

命名規則としては、複数形を基本に、`components`の子ディレクトリだけは単数形にしていますが、好みの問題だと思います

## app

Next.js 13で追加された`App Directory`によるディレクトリです。詳細は割愛しますが、`layout`が使いやすいので`App Directory`が使えるなら使いたいと思ってます

## components

まずは、こちらの記事をご覧ください

https://qiita.com/misuken/items/19f9f603ab165e228fe1

BCD Designは、大規模な開発ではとても有効だと思います。しかし、小規模の開発ならここまで細かく分ける必要がないんじゃないかなと使っていて思ったので、ここでは`base`と`feature`のふたつに分けています

BCD Designにおける迷いにくい粒度や「明名する」という考え方は小規模開発においてもとても有効ですので、積極的に取り入れます

### base

BCD Designにおける`base`に該当します。`atoms`と`molecules`の分け方はBCD Designに準拠します

### feature

BCD Designにおける`domain`に該当します。`domain`は単数形で命名します

BCD Designにおける`case`が存在しないのは、小規模の開発だと私が`case`をうまく使いこなせなかったからです。例えば、

- Button (base)
- AddButton (case)
- UserAddButton (domain)

と分けても、`AddButton`は`UserAddButton`でしか使われないことが多いです。`case`を再利用するのってなかなか難しいんですよね

また、`case`は**専属のディレクトリ化**することが多かったです

例えば、`add`の中に`AddButton`があったとして、それ以外に`addなんちゃら`を作る機会がないとします。これが専属化です

つまり、`add`ディレクトリは`AddButton`を作りたいがために設けられ、その`AddButton`もほとんど再利用されないという遠回り感が生まれてしまうのです。それならば`domain`に統合してしまっていいのではないかということでこの分け方を採用しています。`common`も同様の理由で`domain`に統合しています

色々なディレクトリ構造を見ている方ならお分かりだと思いますが、汎用的な部品(`base`)と機能ごとに分ける(`feature`)やり方は`feature`ディレクトリを採用しているディレクトリ構造と意図がほぼ一緒です

では、なぜわざわざBCD Designについて持ち出したかというと、BCD Designにおける`atoms`と`molecules`の分け方や「明名する」という考え方を取り入れたいと考えたからです

#### atomsとmolecules

`Button`などの単一的なコンポーネントは`atoms`、`Card`や`List`などの複合的なコンポーネントは`molecules`に入れます

`atoms`と`molecules`では1ファイルにpresenterとcontainerの両方を定義します。

```tsx:src/components/feature/hoge/atoms/HogeButton.tsx
export type HogeButtonPresenterProps = {
    children: React.ReactNode
}

export const HogeButtonPresenter = ({children}: HogeButtonPresenterProps) => {
    return <button>...</button>
}

export type HogeButtonProps = {
    ...
}

export const HogeButton = (...) => {
    return <HogeButtonPresenter>...</HogeButtonPresenter>
}
```

presenterは基本的にそのファイル内ぐらいでしか使わないので接尾辞としてPresenterをつけます。しかし、containerは他のところでも頻繁に使われる可能性があり、毎回Containerをつけるのは面倒かつ見栄えが悪いので接尾辞はつけません(慣例的に接尾辞なし===Containerとする)


#### hooks

`hooks`にはそのドメインのスコープでしか使用しないhookを入れます。

#### その他

`hoge.constants.ts`にはそのドメインの定数を、`hoge.types.ts`にはそのドメインのスキーマと型定義を入れます。わざわざディレクトリを切る必要はないと思います

### functional

詳細は以下の記事をご覧ください

https://zenn.dev/yoshiko/articles/99f8047555f700#functional

`functional`はなくてもいいと思います。とりあえず私はRecoilの`RecoilObserver.tsx`を置いています

### page

`feature`は機能を軸に分類しますが、`page`は画面を軸に分類します。`page`で行うのは`feature`を組み合わせることだけです。`src/app/page.tsx`では直接`feature`をimportせず、`src/components/page`を介します。ただし、`src/app/layout.tsx`だけは直接`feature`をimportするのを許可します

## pages

Next.jsの`API Routes`のためのディレクトリです。`API Routes`を使わないなら必要ありません

## hooks

特定の機能にとらわれない汎用的なhookを入れます

## providers

特定の機能にとらわれない汎用的なproviderを入れます。

そもそもproviderはあまり使わないようにします。理由は、`stores`と`hooks`があるのにわざわざ`providers`まで必要になる場面ってなかなかないかなと思ったからです

## types

特定の機能にとらわれない汎用的なスキーマや型定義を入れます。

`types`の中でさらにどのように分けるかは、まだ洗練しきれていないです。正直`types/index.ts`一本でいいような気もしてます。限定的な型は`feature/hoge/hoge.types.ts`で管理してますし、`types`の中でさらに細かく分けるとどの程度の粒度で分ければいいかという問題が生じてしまいます

## stores

Recoilなどの状態管理を伴うhookはここに入れます。詳細は以下の記事をご覧ください

https://zenn.dev/warabi/articles/2521222d57a71f

が、最近Jotaiもなかなか良いなと感じているので、ここの中身は使用している状態管理ライブラリによると思います

## utils

汎用的な関数などを入れます

## libs

ライブラリの設定などを入れます

# その他気をつけること

## TailwindCSS

ReactでTailwindCSSを使う際は以下の記事の内容を参考にします

https://zenn.dev/nyatinte/articles/083ebbe8ab2457

## Storybookやテストファイル

`hoge.stories.tsx`や`hoge.spec.tsx`は対象コンポーネント(`hoge.tsx`)と同階層に置きます。わざわざ`stories`ディレクトリや`__tests__`ディレクトリを設けないということですね

# おわりに

こういうの考えてもどうせ数ヶ月後には変わってるんですよね

BCD Designをもっと上手く使いこなせるようになりたいです