Professional React Development
- 2022年に最も普及するReactの技術スタック
- Screaming Architecture - Reactのディレクトリ構成を進化させる
- プロフェッショナルなReactプロジェクトの立ち上げ方
- React開発者のためのGitワークフローとGitHubセットアップ
(この記事の和訳となっております)
Reactのディレクトリ構成...昔からあるトピックです。しかし、Reactの独創的なアプローチは、頻繁に質問を引き起こします。「どこにファイルを置けばいいのか?どのようにコードを整理すればいいのでしょうか?正直なところ、長年の経験を持ってしても、同じような質問をすることに気づきました。
そこで私は、Reactのプロジェクトを構成する最も一般的なアプローチの概要を知るために調査をしました。その結果は以下の通りです。
- ファイルの種類によるグループ化(例:コンポーネント、コンテキスト、フックに別々のフォルダを設定する)
- コンテキスト、フックなどのグローバルフォルダを使用したページごとのグループ化
- 関連するコンポーネント、コンテキスト、フックのコロケーションによるページごとのグループ化
- 機能別にグループ化
この記事では、成長するコードベースの中で進化するこれらのフォルダー構造と、それらが引き起こす可能性のある問題について、私が観察したことを反映しています。また、ベストプラクティスの短いリストと、今度の講座で紹介するデザインを機能ベースのフォルダー構造に変えるという課題も含まれています。
局所的というよりは大局的な視点で見ていきます。言い換えれば、App.js
ファイルをどこに置くかは、ファイルを整理するための全体的なアプローチよりも重要ではありません。
この物語を盛り上げるために、ある新しいスタートアップが様々なステージを経て、コードベースが成長していく過程を(少し風刺的に)追ってみましょう。独創的なアイデア、次のTodoアプリを作ろう!
プロトタイプ: ファイルタイプでグループ化する
もちろん、私たちのスタートアップには素晴らしいビジョンがあります。破壊、世界征服、ご存知の通りです。しかし、誰もが小さなことから始めなければならないのです。
そこで、Reactのドキュメントから始めます。ディレクトリ構成を決定するのに5分以上かけてはいけないと書いてありました。では、さっそく始めてみましょう。
私たちのTodoスタートアップの最初のバージョンとして、シンプルなTodoアイテムのリストで十分です。これなら、初期のプレシード投資も受けられると思いませんか?
この場合、Reactのドキュメントにある「Grouping by file type」オプションが最もシンプルなディレクトリ構成であると思われる。コンポーネントはcomponents
フォルダに、フックはhooks
フォルダに、コンテキストはcontext
フォルダに、という具合だ。そして、私たちは原始人ではないので、コンポーネントごとにフォルダを作成し、スタイルやテストなどを格納する。
└── src/
├── components/
│ │ # I'm omitting the files inside most folders for readability
│ ├── button/
│ ├── card/
│ ├── checkbox/
│ ├── footer/
│ ├── header/
│ ├── todo-item/
│ └── todo-list/
│ ├── todo-list.component.js
│ └── todo-list.test.js
├── contexts/
│ │ # no idea what this does but I couldn't leave this folder empty
│ └── todo-list.context.js
└── hooks/
│ # again no idea what this does but I couldn't leave this folder empty
└── use-todo-list.js
これはかなりシンプルに見えます。プログラミングが初めての人にとっても、これは素晴らしい、単純な方法です。考えすぎる必要はありません。
しかし、お察しの通り、このシンプルさは長くは続かないでしょう。
投資: ファイル数増加→ネスト化
ToDoアプリの機能は素晴らしいが、資金が足りなくなった。今こそ、投資家を取り込む時です。つまり、進捗を示す必要があります。進捗を示す最善の方法は、新機能を追加することですよね?
天才の私たちにアイディアがあります。TODOアイテムの編集をサポートしないか?素晴らしい ToDo を編集するためのフォームと、フォームを表示するためのモーダルが必要なだけです。
└── src/
├── components/
│ ├── button/
│ ├── card/
│ ├── checkbox/
│ │ # this modal shows a form to edit a todo item
│ ├── edit-todo-modal/
│ ├── footer/
│ ├── header/
│ ├── modal/
│ ├── text-field/
│ │ # here is the form that is shown by the modal
│ ├── todo-form/
│ ├── todo-item/
│ │ # the edit modal is shown on top of the todo list
│ └── todo-list/
│ ├── todo-list.component.js
│ └── todo-list.test.js
├── contexts/
│ ├── modal.context.js
│ └── todo-list.context.js
└── hooks/
├── use-modal.js
├── use-todo-form.js
└── use-todo-list.js
悪くはないのですが、components
フォルダが混雑してきました。checkbox
とtext-field
(ともにフォームフィールド)、edit-todo-modal
とtodo-form
(親と子)といった関連フォルダが離れているのも少し気になる。
コンポーネントをグループ化してコロケーションできるかも?
└── src/
├── components/
│ ├── edit-todo-modal/
│ │ ├── edit-todo-modal.component.js
│ │ ├── edit-todo-modal.test.js
│ │ │ # colocate -> todo-form is only used by edit-todo-modal
│ │ ├── todo-form.component.js
│ │ └── todo-form.test.js
│ ├── todo-list/
│ │ │ # colocate -> todo-item is only used by todo-list
│ │ ├── todo-item.component.js
│ │ ├── todo-list.component.js
│ │ └── todo-list.test.js
│ │ # group simple ui components in one folder
│ └── ui/
│ ├── button/
│ ├── card/
│ ├── checkbox/
│ ├── footer/
│ ├── header/
│ ├── modal/
│ └── text-field/
├── contexts/
│ ├── modal.context.js
│ └── todo-list.context.js
└── hooks/
├── use-modal.js
├── use-todo-form.js
└── use-todo-list.js
このディレクトリ構成により、重要な機能の概要を把握しやすくなりました。components
フォルダーのごちゃごちゃは、2つの方法で取り除きました。
- 子コンポーネントを親にコロケーションすることで、親コンポーネントと子コンポーネントを分離することができます。
- 汎用的なUIやレイアウトのコンポーネントを
ui
フォルダにまとめることで、より使いやすくなりました。
フォルダを折りたたむと、よりすっきりした構造が見えてきます。
└── src/
├── components/
│ ├── edit-todo-modal/
│ ├── todo-list/
│ └── ui/
├── contexts/
└── hooks/
成長: ページが必要
私たちのスタートアップは成長を続けています。アプリを一般に公開し、一握りのユーザーしかいません。もちろん、彼らはすぐに不満を持ち始めます。最も重要なのは
ユーザーは、自分でTodo項目を作りたい!と思っています。
少し考えれば、簡単な解決策が見つかります。ユーザーがフォームを介してTODOを作成できる2番目のページを追加するのです。幸運なことに、このフォームはTODOの編集に再利用できます。開発チームの貴重なリソースを節約できるのですから、これは素晴らしいことです。
とにかく、カスタム ToDo アイテムを持つということは、ユーザー エンティティと認証が必要だということです。ToDo フォームは "create todo page" と "edit todo modal" の間で共有されるので、再び components
フォルダに移動させます。
└── src/
├── components/
│ │ # we now have multiple pages
│ ├── create-todo-page/
│ ├── edit-todo-modal/
│ ├── login-page/
│ │ # this is where the todo-list is now shown
│ ├── home-page/
│ ├── signup-page/
│ │ # the form is now shared between create page and edit modal
│ ├── todo-form/
│ ├── todo-list/
│ │ ├── todo-item.component.js
│ │ ├── todo-list.component.js
│ │ └── todo-list.test.js
│ └── ui/
├── contexts/
│ ├── modal.context.js
│ └── todo-list.context.js
└── hooks/
│ # handles the authorization
├── use-auth.js
├── use-modal.js
├── use-todo-form.js
└── use-todo-list.js
今のディレクトリ構成はどうでしょうか?いくつか問題があるように思います。
まず、components
フォルダがまた膨れ上がってきました。しかし、ディレクトリ構成をある程度フラットに保ちたいのであれば、これを避けることはできないでしょう。なのでこの問題は無視することにします。
次に(もっと重要なことですが)、components
フォルダには、さまざまな種類のコンポーネントが混在しています。
- ページ (アプリのエントリポイントであり、新しい開発者がコードベースを理解するために重要です)
- 副次的に使われる可能性があるコンポーネント(formなど)
- ボタンのようなシンプルなUIコンポーネント
解決策: pages
フォルダーを別に作成します。すべてのページ・コンポーネントとその子コンポーネントをそこに移動させます。複数のページに表示されるコンポーネントだけが、components
フォルダーに残ります。
└── src/
├── components/
│ │ # the form is shown on the home and create todo page
│ ├── todo-form/
│ │ # we could also ungroup this folder to make the components folder flat
│ └── ui/
├── contexts/
│ ├── modal.context.js
│ └── todo-list.context.js
├── hooks/
│ ├── use-auth.js
│ ├── use-modal.js
│ ├── use-todo-form.js
│ └── use-todo-list.js
└── pages/
├── create-todo/
├── home/
│ ├── home-page.js
│ │ # colocate -> the edit modal is only used on the home page
│ ├── edit-todo-modal/
│ └── todo-list/
│ ├── todo-item.component.js
│ ├── todo-list.component.js
│ └── todo-list.test.js
├── login/
│ # don't forget the legal stuff :)
├── privacy/
├── signup/
└── terms/
私にとっては、この方がずっとすっきりして見えます。新しい開発者が入社したとき、すべてのページを簡単に識別できるようになりました。これによって、コードベースを調査したり、アプリケーションをデバッグしたりするための入口を得ることができるのです。
これは、多くの開発者が使っている一般的なディレクトリ構成のようです。以下はその2例です。
- Tania Rascia氏は同様のディレクトリ構成を提案し、より詳しく説明しています。
- Max Rozen氏は、同様のディレクトリ構成にいくつかのガイドラインを追加して使用しています。
しかし、私たちのスタートアップの目標は、世界を征服することですから、当然、ここで立ち止まるわけにはいきません。
世界征服: コロケーション
本格的なビジネスに成長しました。世界で最も人気のあるTodoアプリ(5つ星評価)。誰もが私たちのスタートアップにお金を注ぎ込もうとします。私たちのチームは成長し、それに伴いコードベースも大きくなりました。
└── src/
├── components/
├── contexts/
│ ├── modal.context.js
│ ├── ... # imagine more contexts here
│ └── todo-list.context.js
├── hooks/
│ ├── use-auth.js
│ ├── use-modal.js
│ ├── ... # imagine more hooks here
│ ├── use-todo-form.js
│ └── use-todo-list.js
└── pages/
すみません、創造力を使い果たしました。要点はわかってもらえたと思います。グローバルhooks
とcontexts
フォルダが大きくなってきました。
同時に、より複雑なコンポーネントのコードは、まだ複数のフォルダーに散らばっています。コンポーネントはpages
フォルダのどこかに住み、components
フォルダの共有コンポーネントを使い、contexts
やhooks
フォルダのビジネスロジックに依存しているかもしれません。コードベースが大きくなると、これではファイル間の依存関係を追跡したり、絡み合ったコードを促進したりするのがかなり難しくなります。
解決策:コロケーション!可能な限り、コンテキストとフックを、それらが使用されるコンポーネントの隣に移動させます。
└── src/
├── components/
│ ├── todo-form/
│ └── ui/
├── hooks/
│ │ # not much left in the global hooks folder
│ └── use-auth.js
└── pages/
├── create-todo/
├── home/
│ ├── home-page.js
│ ├── edit-todo-modal/
│ └── todo-list/
│ ├── todo-item.component.js
│ ├── todo-list.component.js
│ ├── todo-list.context.js
│ ├── todo-list.test.js
│ │ # colocate -> this hook is only used by the todo-list component
│ └── use-todo-list.js
├── login/
├── privacy/
├── signup/
└── terms/
グローバルcontexts
フォルダを削除しました。残念ながら、use-auth
ファイルを置くのに良い場所がないので、グローバルhooks
フォルダは今のところそのままです。いい方法ではないが、グローバルフォルダは少ないほうがいいのです。すぐにゴミ捨て場になってしまうからです。
このディレクトリ構成の最も重要な利点: ある機能に属するすべてのファイルを一度に把握することができる。一つのコンポーネントのコードを探すために、5つの異なるフォルダーを見る必要はありません。
しかし、同時にまだ問題も残っています。
- todo "エンティティに関連するコードは、複数のフォルダーに分散しています。エンティティを追加し始めると、ちょっと面倒になりそうです。
- ディレクトリ構成を見ただけで、
Todo-list
コンポーネントがhome
フォルダにあると推測できますか?
└── src/
├── components/
├── hooks/
└── pages/
├── create-todo/
├── home/
├── login/
├── privacy/
├── signup/
└── terms/
EXIT: 機能別グループ
夢が叶った!スタートアップを数十億円で売却することになりました。私たちはユニコーンを作りました🦄 FAANGT.
しかし、成功には責任が伴います。ユーザーは新しい機能を求めているのです。またもやです。特に重要なのは、仕事のToDo項目と買い物リストのToDo項目を分けて、別のプロジェクトを作りたいという要望です。誰が想像できたでしょうか...。
解決策:Todo項目のリストを含む新しい「project」エンティティを追加します。
2つの新しいページを追加することにしました。ひとつはプロジェクトを作成するためのページ、もうひとつはプロジェクトをTODOも含めて表示するためのページです。トップページも同様に変更しなければなりません。すべてのプロジェクトのリストと、すべてのTODOのリストを表示する必要があります。
つまり、Todo-list
コンポーネントは2つのページで使用されているので、components
フォルダに移動する必要があります。
└── src/
├── components/
│ ├── todo-form/
│ │ # is now shared between home and project page
│ ├── todo-list/
│ │ ├── todo-item.component.js
│ │ ├── todo-list.component.js
│ │ ├── todo-list.context.js
│ │ ├── todo-list.test.js
│ │ └── use-todo-list.js
│ └── ui/
└── pages/
├── create-project/
├── create-todo/
│ # shows now a list of projects and an overview of all todos
├── home/
│ ├── index.js
│ ├── edit-todo-modal/
│ └── project-list/
├── login/
├── privacy/
│ # shows a list of todos belonging to a project
├── project/
├── signup/
└── terms/
これでもかなり綺麗に見えます。しかし、2つの問題が見えてきました。
・pages
フォルダを見ても、このアプリに todo、project、user があることはすぐにはわかりません。理解はできますが、まずはcreate-todo
(Todoのエンティティ)やlogin
(ユーザーのエンティティ)などのフォルダ名を処理し、重要でないもの(privacy
やterms
など)から分離する必要があります。
・複数のページで使われるからといって、共有components
フォルダに愚直にコンポーネントがあるのは恣意的な感じがします。どのフォルダにあるのかを理解するためには、そのコンポーネントがどこで、何箇所使われているのかを知る必要があります。
IDEを使えば、ファイル名でファイルを開くことができます(例:VS Codeで「Ctrl + P」)。その通りです。しかし、そもそも名前を覚えていないのであれば、それはあまり役に立ちません。ですから、私の観点では、コードベースを複数の方法でナビゲートできれば常に良いと考えています。
最後にもう一度、ディレクトリ構成を調整し、ファイルを機能ごとにグループ分けしてみましょう。
「機能」というのはかなり広い意味の言葉なので、何を意味するかは自由です。この場合、エンティティ(todo
、projects
、users
)と、ボタンやフォームフィールドなどのコンポーネントのためのui
フォルダの組み合わせにします。
└── src/
├── features/
│ │ # the todo "feature" contains everything related to todos
│ ├── todo/
│ │ │ # this is used to export the relevant modules aka the public API (more on that in a bit)
│ │ ├── index.js
│ │ ├── create-todo-form/
│ │ ├── edit-todo-modal/
│ │ ├── todo-form/
│ │ └── todo-list/
│ │ │ # the public API of the component (exports the todo-list component and hook)
│ │ ├── index.js
│ │ ├── todo-item.component.js
│ │ ├── todo-list.component.js
│ │ ├── todo-list.context.js
│ │ ├── todo-list.test.js
│ │ └── use-todo-list.js
│ ├── projects/
│ │ ├── index.js
│ │ ├── create-project-form/
│ │ └── project-list/
│ ├── ui/
│ │ ├── index.js
│ │ ├── button/
│ │ ├── card/
│ │ ├── checkbox/
│ │ ├── header/
│ │ ├── footer/
│ │ ├── modal/
│ │ └── text-field/
│ └── users/
│ ├── index.js
│ ├── login/
│ ├── signup/
│ └── use-auth.js
└── pages/
│ # all that's left in the pages folder are simple JS files
│ # each file represents a page (like Next.js)
├── create-project.js
├── create-todo.js
├── index.js
├── login.js
├── privacy.js
├── project.js
├── signup.js
└── terms.js
なお、各フォルダにはindex.js
ファイルを導入しています。これらはモジュールやコンポーネントの公開APIと呼ばれることが多いです。もしこの意味がわからない場合は、以下でより詳しい説明をご覧ください。
しかし、その前に新しい「機能別グループ」ディレクトリ構成について説明します。
ディスカッション: 機能駆動型ディレクトリ構成とScreamingアーキテクチャ
Screaming Architectureという記事の中で、ボブ・マーティン氏はこう言っている。
あなたのアーキテクチャは、あなたがシステムで使用したフレームワークについてではなく、システムについて読者に伝えるべきものです。もしあなたがヘルスケアシステムを構築しているなら、新しいプログラマーがソースリポジトリを見たとき、彼らの第一印象はこうなるはずです。「ああ、これは医療システムなんだ」と。
ここで、最初のディレクトリ構成を思い出してみましょう。ファイルの種類ごとにグループ化されています。
└── src/
├── components/
├── contexts/
└── hooks/
これは、システムまたはフレームワークについて何かを教えてくれるのでしょうか?このディレクトリ構成は、こう叫びます。「私はReactアプリです。」
最終的な機能別ディレクトリ構成はどうでしょうか。
└── src/
├── features/
│ ├── todo/
│ ├── projects/
│ ├── ui/
│ └── users/
└── pages/
├── create-project.js
├── create-todo.js
├── index.js
├── login.js
├── privacy.js
├── project.js
├── signup.js
└── terms.js
どのフレームワークを使用したかは不明です。しかし、このディレクトリ構成は「おい、俺はプロジェクト管理ツールだぞ」と言わんばかりに目に飛び込んでくるのです。
ボブ・マーティン氏が言ってるのとよく似てるね。
記述的なアーキテクチャとは別に、features
とpages
によって、開発者はアプリケーションへの2つの異なるエントリーポイントを得ることができます。
- あるコンポーネントを変更する必要があり、それがホームページにあることだけが分かっている場合、
pages/home.js
を開き、リファレンスをクリックするとそのコンポーネントが表示されます。 -
TodoList
を変更する必要があるが、どこで使われているかわからない場合、features/todo
フォルダを開くだけで、その中のどこかにあるはずです。
そして最後に、グローバルcontexts
とhooks
フォルダを削除しました。必要であれば、まだそれらを再導入することができます。しかし、少なくとも現時点では、これらの潜在的なゴミ捨て場を取り除いたのです。
個人的にはこのディレクトリ構成にとても満足していますが、もっとfeatures
内のディレクトリ構成をきれいにすることもできるかもしれません。例えば、現在todo
フォルダは少しごちゃごちゃしているように見えます。Alan Alickovicの素晴らしいサンプルプロジェクトBulletproof Reactでは、各機能内のファイルをファイルタイプ別に分けることを提案しています(私たちが最初に行ったように)。
しかし、私の見解では現在のディレクトリ構成は十分にクリーンで説明的です。「features」が自己完結しているため、必要であれば簡単にリファクタリングできるはずです。同時に、私たちのディレクトリ構成は最初からプロジェクトで使用するのに十分なほど単純なものです。これは長い目で見れば、私たちの頭痛の種を減らすことができるかもしれません。
私の経験では、多くのプロジェクトがこのページで説明されているような方法で発展しています。しかし、時間的なプレッシャーから、開発者はディレクトリ構成をきれいにする機会がありません。そのため、プロジェクトはさまざまなアプローチが混在した状態で終わってしまうのです。機能主導のディレクトリ構成から始めると、長い目で見てアプリをきれいに保つことができます。
機能主導のフォルダー構造について深く知りたい方は、こちらの資料もご覧ください。
・Bulletproof Reactのソースコード と、その ディレクトリ構成に関するドキュメントです。
・Swyx氏のツイート
・Kolby Sisk氏による素晴らしいブログ記事で、より詳しく紹介されています。
・この記事のきっかけとなったRobin Wieruch氏のブログ記事(Robin氏はファイルを種類別にグループ化するのが好きなようですが)。
・Feature Sliced - フロントエンドプロジェクトのためのアーキテクチャ手法(残念ながら英語版は未完成です)。
ベストプラクティス
絶対インポート
features/todo/todo-list
ファイル内のTodoリストコンポーネントのボタンをレンダリングする場合を考えてみましょう。デフォルトでは、相対インポートを使用することになります。
import { Button } from "../../ui/button";
...
特にリファクタリング時にファイルを移動させる場合、../..
による相対パスの管理が面倒になることがあります。また、いくつの ..
が必要なのか、すぐに当てずっぽうになってしまいます。
代替案として、絶対インポートを使用することができます。
import { Button } from "@features/ui/button";
...
これで、TodoList
コンポーネントをどこに移動させても問題ありません。インポートパスは常に同じになります。
Create React Appでは、絶対的なインポートの設定が非常に簡単である。jsconfig.json
ファイル(TypeScriptの場合はtsconfig.json
)を追加して、パスのエイリアスを定義するだけです。
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@features/*": ["src/features/*"],
}
}
}
Reactについてはこちら、Next.jsについてはこちらで、より詳しいチュートリアルをご覧いただけます。
index.jsをpublic APIとする
最終的なディレクトリ構成では、各機能とコンポーネントのフォルダにindex.js
を追加しています。ここで、簡単な注意事項です。
── src/
├── features/
│ ├── todo/
│ │ │ # this is used to export the relevant modules aka the public API
│ │ ├── index.js
│ │ ├── create-todo-form/
│ │ ├── edit-todo-modal/
│ │ ├── todo-form/
│ │ └── todo-list/
│ │ │ # the public API of the component (exports the todo-list component and hook)
│ │ ├── index.js
│ │ ├── todo-item.component.js
│ │ ├── todo-list.component.js
│ │ ├── todo-list.context.js
│ │ ├── todo-list.test.js
│ │ └── use-todo-list.js
│ ├── projects/
│ ├── ui/
│ └── users/
└── pages/
前述のように、このindex.jsファイルは、モジュールやコンポーネントのpublic APIと呼ばれることが多い。
しかし、それはどういう意味なのでしょうか?
features/todo/todo-list
フォルダーにあるインデックスファイルの例を示します。
import { TodoList } from "./todo-list.component";
import { useTodoList } from "./use-todo-list";
export { TodoList, useTodoList };
このファイルは、単にいくつかのモジュールをインポートしたりエクスポートしたりするだけです。以下はさらに短いバージョンです。
export { TodoList } from "./todo-list.component";
export { useTodoList } from "./use-todo-list";
また、feature/todo/index.js
というファイルは、そのサブフォルダからすべてをエクスポートするだけです。
export * from "./create-todo-form";
export * from "./todo-list";
// ... and so on
それが私たちの役に立つのでしょうか?
ファイルpages/home
の中にTodoList
コンポーネントをレンダリングすることを想像してください。このようにネストされたフォルダーからインポートするのではなく
import { TodoList } from "@features/todo/todo-list/todo-list.component";
...
Todo機能から直接インポートすることができます。
import { TodoList } from "@features/todo";
...
これには、いくつかのメリットがあります。
- よりきれいに見えます。
- 開発者は、ある機能のコンポーネントの1つを使用するために、その機能の内部ディレクトリ構成を知る必要はありません。
- どのコンポーネントなどを外部に公開するかを定義することができます。インデックスファイルに書き出したものだけが、アプリの他の部分で使われるはずです。残りは内部/非公開です。だから「public API」という名前なのです。
- 公開APIが変わらない限り、機能フォルダ内のすべてのものを移動したり、名前を変更したり、リファクタリングしたりすることができます。
ファイル名とフォルダ名のケバブケース
私は以前、他の多くの人と同じようにコンポーネントファイルにはパスカルケース(例:MyComponent.js
)、関数/フックにはキャメルケース(例:useMyHook.js
)を使って名前を付けていました。
MacBookに乗り換えるまでは。
リファクタリングセッションで、myComponent.js
というコンポーネントファイルの名前を正しい形式のMyComponent.js
に変更しました。ローカルではすべてうまくいったのですが、なぜかGitHub上のCIが文句を言い始めました。それは、以下のimport文がおかしいと主張した。
import MyComponent from "./MyComponent";
MacOSはデフォルトで大文字小文字を区別しないファイルシステムであることが判明しました。MyComponent.js
とmyComponent.js
は同じものです。そのため、Gitはファイル名の変更を拾ってくれませんでした。残念なことに、GitHub上のCIはLinuxのイメージを使っていました。そして、これは大文字と小文字が区別されるのです。そのため、私のCIによればファイルが存在しないのに、私のローカルマシンはすべてOKだと言っていたのです。
これを理解するのに何時間もかかりました。そしてどうやら、この問題にぶつかったのは私だけではないようです。
解決策:ファイル名やフォルダ名にケバブケースを使用します。
例えば
・MyComponent.js
の代わりにmy-component.js
と記述してください。
・useMyHook.js
の代わりにuse-my-hook.js
と記述してください。
これは、Next.jsがデフォルトで使用しているものです。Angularはコーディングスタイルガイドにこれを含めています。kebab-caseを使わない理由は見当たりませんが、あなたやあなたのチームメイトの頭痛の種を減らすことができるかもしれません。
課題:このデザインをもとに、あなたならどのようにプロジェクトを構成しますか?
これは、今度のコースにあるウェブアプリ(例えばSentryのような)用のエラーログツールのデザインです。
- このアプリの根幹をなす主体は「組織」です。
- 各組織には、プロジェクトとユーザーが割り当てられています。
- 各プロジェクトには課題(組織のWebサイトから送信されるエラーなど)があります。
- 左のナビゲーションの項目は、それぞれページを表しています。
このデザインを機能ベースのディレクトリ構成にするにはどうしたらいいでしょうか?
答え
└── src/
├── features/
│ ├── alerts/
│ ├── issues/
│ │ # this contains the settings
│ ├── organization/
│ ├── projects/
│ │ ├── index.js
│ │ ├── project-card.js
│ │ └── project-list.js
│ ├── ui/
│ │ ├── index.js
│ │ ├── card/
│ │ ├── header/
│ │ ├── footer/
│ │ ├── side-navigation/
│ │ └── tag/
│ └── users/
└── pages/
├── alerts.js
├── issues.js
├── projects.js
├── settings.js
└── users.js