Next.js + サーバーサイドTypeScript + 関数フレーバーでクリーンなアプリを作ったので実装意図とか書く Advent Calendar 2022
の16日目。株式会社mofmofに生息しているshwldです。
前日はTurbopackについて書きました
Next.js/React + GraphQLのコンポーネント整頓術
Next.jsはまだversion12を使っています。早く13になりたい。
コンポーネントの整理はbulletproof-reactを参考にしています。
┣━ components: 全体で共有するドメイン知識を持たないコンポーネント
┣━ features: 機能ごとのコンポーネント群
┗━ pages: Next.jsが管理するページ
この3つのディレクトリに分かれています。
components
, pages
にはあまりコンポーネントは増えません。
components
全体で共有するコンポーネントはあまり多くなく、ここにコンポーネントが増える場合は注意が必要くらいに考えています。
ドメイン知識を持たないと書いてますが、layoutをここに入れてしまっています。layoutは別で切ってもいいかなとか思ったりします。
pages
基本的にはほとんどコードを書かず、features配下のコンポーネントを呼び出すのみです。
urlをファイルベースで表現するためにあるくらいの薄い層です。
features
メインとなるディレクトリです。
機能ごとにディレクトリを切り、コンポーネントを配置しています。
コンポーネントの依存をツリーで表すことを優先して整理したいと思っていて、あるコンポーネント配下で使うコンポーネントは、そのディレクトリより下位に存在するようにします。
つまりこのディレクトリ配下は依存が深ければそれだけディレクトリも深くなります。
共通のfunctionやhookもなるべく作りたくなく、可能な限りfeatures
配下の依存するコンポーネントの近くに置きます。
依存が明確になると、もしコンポーネントを使わなくなっても、枝の上の方で切り落せば含まれる要素すべてをきれいに削除することができます。
GraphQLのクエリ
GraphQLは書くfeatureコンポーネントが実行します。
依存ツリーの途中で実行するべきか、ルートで実行すべきかは場合によるので適宜判断して配置します。
実行するGraphQLクエリは基本的にはそのコンポーネント以外から使わないため、同じディレクトリの中に同居させます(コロケーション)
また、命名がかぶらないよう、クエリの命名規則として コンポーネント名_
を先頭につけるようにしています
fragment StoryCreateForm_Item on Story {
id
title
}
/apps/web/src/features/project/ProjectBoard/components/StoryCreateForm/StoryCreateForm.graphql
プレゼンテーショナル、コンテナーなコンポーネントは特に区別する必要はないと思っており、どこからでもクエリしていいと思って実装しています。
上記を意識して実装するとバケツリレーまみれになるし、データと表示を切り離したとしてカスタマイズして使うことはほぼありません、テストもモックしてしまえば問題ありません。
この方針にすることのデメリットはコンポーネントが完全にGraphQLのクライアントに依存することで、GraphQLなしでの実装は想定されていません。
自分はプレゼンテーショナルとコンテナが分離しているとファイルが増え、型定義も増え、DXが悪いと感じるので、デメリットを受け入れました。
Next.jsを使う理由
あまりSSRを活用するというプロダクトでもないので、Next.jsを使う大きな理由はセットアップの楽さになります。
次回予告
次回はNextAuth.jsとAuth0を使って認証をパッと作るについて書きます。