#はじめに
Webサービス BUZZ STOCK .COMを個人開発しているのですが(ただのポートフォリオだろとか言わない!)、フロントエンドはNext.js+TypeScriptで構築しています。
Next.jsのプロジェクトのディレクトリ構成については、案件の規模・仕様などによって様々あると思いますが、今回一例として紹介させていただきます。
現在の画面数は5ページでコンポーネントは15個ほどになっています。
サービスの現在の機能は株式チャートの表示機能とTwitterクローン的な機能になっております。(よければ確かめてやってください)
使用技術
- 状態管理 useContext
- データフェッチ ブラウザ標準APIのfetchメソッド, SWR(ISRでレンダリングするページのキャッシュ使えそうなところなどで使用)
- CSS CSS Modules(SCSS)
#ディレクトリ構成
root/
├── build
├── public/
│ ├──fonts
│ └──images
└── src/
├── components/
│ ├── common
│ │ ├── Footer.module.scss
│ │ ├── Footer.tsx
│ │ ├── Navigation.module.scss
│ │ ├── Navigation.tsx
│ │ └── 〜〜〜〜
│ ├── chart
│ ├── profile
│ └── 〜〜〜〜
├── pages/
│ ├── app.tsx
│ ├── app.scss
│ ├── index.tsx
│ ├── index.scss
│ ├── reset.scss
│ ├── variables.scss
│ ├── account
│ │ ├── Auth.module.scss
│ │ ├── login.tsx
│ │ └── signup.tsx
│ │
│ ├── quote
│ │ ├── Ticker.module.scss
│ │ └──[ticker].tsx
│ └── 〜〜〜〜
├── service/
│ ├── auth
│ │ ├──signup.service.ts
│ │ └──login.service.ts
│ ├── follow
│ │ └── follow.service.ts
│ └── 〜〜〜〜
├── type/
│ ├── AuthUserContext.type.ts
│ ├── Favorite.type.ts
│ └── FetchQuery.type.ts
└── utils/
├── auth.ts
├── chartUtil.ts
├── formatDate.ts
└── 〜〜〜〜
‥どうですかね、ツッコミどころはあるかもしれませんが、もし、このディレクトリ構成を見てあなたがそれぞれのファイルの中身が概ね想像できたら、私のディクレトリ構成は成功しているということになります!
##SCSSの置き場所
これ、悩みました。
styleディレクトリを切ってその中に入れるか、コンポーネントフォルダの中に入れるかの2パターン考えられると思います。
今回、私は、コンポーネントフォルダに入れる方を選択しました!
理由としては、まず、コンポーネントを増やすたびにstyleディレクトリの中に同ディレクトリをつくるのが手間だから、という怠慢が一つありますが、コンポーネントの横にstyleファイルを置いておくのは様々な面で楽になります。相対パスでインポートするときとか、エディターで横に開くときとか‥
それに、Reactでコンポーネントベースで構築していくときはスタイルをできるだけコンポーネント固有のものに閉じ込めておいた方がいいと思いますが(CSSによって定義されたコンポーネントではなく、Reactコンポーネントを再利用する為)、その意識もより徹底されやすいかなと思います。
CSS設計につきましては、こちらの記事で大ボリュームの議論を展開させていただきましたので、お時間あるときにお読みくだされば幸いです。
『えっ、でも Next.jsのpagesディレクトリにSCSSファイル置くのってどうなの‥』
これも悩みました‥。Next.jsのpagesディレクトリは、Nextによってルーティングが設定される特別な意味を持つディレクトリです。
ここは聖域にしておいた方がいいのではないか‥。
しかし、このディレクトリにscssファイルを置いてもbuild結果には影響を及ばさないこと・pageもまた一つのReactコンポーネントであり、コンポーネントの横に紐づくスタイルファイルを置くというルールを一貫できること の2つの理由でpagesディレクトリにもscssファイルを置くという蛮行を決意しました。(汗
##components/ pages/ ディレクトリについて
これらのディレクトリにはJSX(TSX)ファイルと、紐づくスタイルファイルが入ります
Reactの state,hooks,rendering などの『データの流れとレンダリング』に関わるロジックがJSX(TSX)ファイルには入ります。
Reactのレンダリングロジックとダイレクトには絡んでこない処理についてはなるたけ、JS(TS)ファイルとして別ディレクトリに切り分けるようにしています。
その他、あえて特筆して書くとすれば、Atomic Designは採用していません。
Atomic Designを何故採用しないのかということも上で紹介したCSS設計の記事に書かせていただいたのですが、要約するとUIデザインの方法論として考えられたAtomic Designをコーディングの設計に利用するのが必ずしも最適ではないと考えている為であります。moleculesかorganismsかという分類分けのコストは、制作するとき、修正するとき、コードレビューするとき、ファイルを探すとき‥全てのプロセスで不要なコストを生みかねないと考えています‥
このディレクトリに入るファイルネームは 〜.tsx となります
##service ディレクトリ
こちらのディレクトリには主に、APIとの通信処理・必要な場合はデータの加工の部分を入れています。
const loginRequest = async (formData: FormData): Promise<any> => {
const url = baseRequestUrl + '/auth/signin';
const result = await fetch(url, {
method: 'POST',
mode: 'cors',
credentials: 'include',
body: formData,
})
.then((response) => response.json())
.catch((error) => {
console.error('Error:', error);
});
return result;
};
export { loginRequest };
こういう処理はJSXから切り分けるとファイルの見通しがよくなり、サッパリします。
このディレクトリに入るファイルネームは 〜.service.ts となります。
##type ディレクトリ
TypeScriptの型定義ファイルが入っています。
怠慢により anyで誤魔化してる部分も多々あるのですが‥ ちゃんと定義してる型はここに入っています。
このディレクトリに入るファイルネームは 〜.type.ts となります。
##utils ディレクトリ
様々な場面で必要となるJSの処理ロジックをここに書いてあります。
const Authentication = {
removeCookie() {
Cookies.remove('expires');
Cookies.remove('jwt');
},
// 有効期限内の場合はtrueを返す
isAuthenticated() {
return new Date().getTime() < parseInt(Cookies.get('expires')!);
},
〜〜〜〜
〜〜〜〜
これらの処理は色々なところから呼び出されます。
このディレクトリに入るファイルネームは 〜.ts となります。
##終わりに
現状のコードサイズでは、これくらいのディレクトリの切り方でも十分、管理できているかなと思っています。
責務によるコードの分割と依存の制御は十分に出来ているかな‥と。
ディレクトリ構成はサービスの変化とともに、変わっていくものであると思いますので、また進化したら更新していきたいと思います。
弁護士ドットコムライブラリーのフロントエンドのアーキテクチャ(Next.js + TypeScript)
こちらの記事などには、実際の企業で運用されているNext.jsプロジェクトのアーキテクチャが詳細に説明されているので、より深く考えたい方などは是非、参考になさられるとよいのではないでしょうか?
こちらの記事のディレクトリ構成が、Next.jsのディレクトリ構成ってどないな感じですればええの?って方の叩き台程度にでもなれば、筆者としては幸いです。
あと、もっとこうした方がいいよ!ってアイデアあれば優しく教えてください(笑
『クリーンアーキテクチャ』実はまだ読めてないので、しっかり読みます!