Towards a reactjs folder structure based on intent
The content here is under the Attribution 4.0 International (CC BY 4.0) license
This post is geared towards a reactjs folder structure based on roles, that aims to favor:
- intent
- communication
Both of them are connected in somehow and in this post I am going to address the issue that is to organize reactjs components in a “meaningful” way, given that the official reactjs documentation does not provide an official file structure [1].
Even tough there are attempts for structuring reactjs [2] apps none has gotten an official stamp, probably it will not happen, but it is possible to become a common standard. Monica Lent also touches on this specific point on her talk, arguing that frontend applications have a different directory structure everyday.
The default
React create app (RCA) comes with no opinion in how you should structure your
components. As it is a unofficial approach to create a folder named components
,
and uses it to hold all components needed for the application. A
basic RCA scaffolding looks like:
├── node_modules
├── package.json
├── package-lock.json
├── public
│ ├── favicon.ico
│ ├── index.html
│ ├── logo192.png
│ ├── logo512.png
│ ├── manifest.json
│ └── robots.txt
├── README.md
└── src
├── App.css
├── App.js
├── App.test.js
├── index.css
├── index.js
├── logo.svg
├── reportWebVitals.js
└── setupTests.js
As the scaffolding does not provides any kind of guidance on structuring the folders by default, I assume that this is on purpose, and the reactjs team doesn’t really care about it. Therefore, it opens a wide range of options, for use, developers to create such a structure.
Its been a few years since I started to work with reactjs and since then, I will make a bullet list of the structures that I have used over the last few years:
├── LICENSE
├── node_modules
├── package.json
├── package-lock.json
├── postcss.config.js
├── public
│ ├── assets
│ ├── docs
│ ├── favicon.ico
│ ├── index.html
│ ├── lemming.js
│ └── manifest.json
├── README.md
├── src
│ ├── actions
│ ├── components
│ ├── constants
│ ├── css
│ ├── emitter
│ ├── engine
│ ├── index.spec.ts
│ ├── index.tsx
│ ├── locale
│ ├── pages
│ ├── queue
│ ├── react-app-env.d.ts
│ ├── reducers
│ ├── registerServiceWorker.js
│ ├── scss
│ ├── setupTests.ts
│ ├── store
│ ├── tailwind.js
│ └── __test__
└── tsconfig.json
From that structure, the only thing that is easy to follow is the lack of organization. At least
for me, it is hard to tell, which part has what and where I can find a specific
piece of code that I am interested in. This is the first issue mentioned earlier
in the post, the intent
issue. As such there is no clear intent of what the
things are.
The common pattern during the development was to drop any file into a subfolder
of src
, leading to a structure that does not express any meaning for
the project itself.
Related work
There are attempts to structure reactjs applications in a opinionated way and without a consensus. For that reason, developers publish materials such as this one aimed to create a standard.
For example, [3] states in the blog post a better way to structure reactjs projects following a principle of responsibilities and adapters. Therefore, it is shallow in the content of the intent. It assumes that the project uses context, which might vary from project to project.
Even the official website from reactjs offers a file structure to be a pattern across reactjs applications [1], therefore, it gives a few common approaches such as grouping by features and grouping by file type.
A new approach
As a developer, for me intent
and communication
is a key player for developing
applications. The goal is to understand as fast as possible the intent
and
keep progressing in the development cycle. For that, I found a folder structure
that makes me comfortable to work with. The structure is based on intent
and
communication
.
The structure has three main pillars, named:
- UI (user interface)
- Third party
- Data flow
- Packages
The division between those two approaches are inspired by different architectural styles such as hexagonal architecture [4] and clean architecture [5].
Starting from the UI, this is the place to have visual components. I call visual components, pure components without complex logic. For example, a container component can be a visual component as well.
Third party is the place to wrap third party libraries that the application depends on, usually the third party is a dependency that is used across files and in different places. Moment is an example of third party library that falls on this category.
Data flow, is the place to have everything related to the data that the UI depends on. As such, this is the place for redux, mobx or any other library that handles data flow and has data itself.
The gotcha for this structure I believe for any complex application, lies in
the gray area, between components, and how they communicate. To address this issue
I suggest to use a specific place, a specific folder, named packages
.
The packages
folder, in general would have a strict business rule, as such,
it is the place to have, in this case, pure javascript/typescript code.
POC
The structure presented in the previous section was applied to the same project presented in the section The default.
├── src
│ ├── components
│ │ ├── app
│ │ └── ui
│ ├── config.ts
│ ├── css
│ │ ├── index.css
│ │ └── tailwind.css
│ ├── data-flow
│ │ └── redux
│ ├── index.spec.ts
│ ├── index.tsx
│ ├── packages
│ │ ├── emitter
│ │ ├── engine
│ │ ├── queue
│ │ └── types
│ ├── pages
│ │ ├── completed-end
│ │ ├── completed-intro
│ │ ├── introduction
│ │ ├── login
│ │ ├── notfound
│ │ ├── rocket-01
│ │ ├── rocket-02
│ │ ├── rocket-03
│ │ ├── survey
│ │ ├── tdd
│ │ ├── tdd-intro
│ │ ├── tutorial
│ │ ├── tutorial-end
│ │ ├── unit-testing
│ │ ├── unit-testing-end
│ │ └── unit-testing-intro
│ ├── react-app-env.d.ts
│ ├── registerServiceWorker.js
│ ├── scss
│ │ ├── attention.scss
│ │ ├── fade-in-left.scss
│ │ ├── fade-out-left.scss
│ │ ├── levelup-animation.scss
│ │ ├── logo-animation.scss
│ │ ├── shake-horizontal.scss
│ │ └── tailwind.src.scss
│ ├── setupTests.ts
│ ├── tailwind.js
│ ├── __test__
│ │ ├── stubs
│ │ ├── withintlProvider.js
│ │ └── withReduxProvider.js
│ └── third-party
├── static.json
├── stryker.conf.js
├── styleguide.config.js
└── tsconfig.json
Future work
The proposed architecture for reactjs applications require adoption to test if the approach brings any benefit or degrades any aspect of the software life cycle development. Besides that, the suggested approach can be applied for different frameworks or libraries, it is not coupled to reactjs. As such, further analysis is required to investigate the fit for other popular frameworks.
Related subjects
References
- [1]Reactjs, “File Structure,” 2021 [Online]. Available at: https://reactjs.org/docs/faq-structure.html. [Accessed: 09-Feb-2021]
- [2]I. L. I. A. KNIAZEV, “The Essentials of a React Application Architecture,” 2021 [Online]. Available at: https://javascript.plainenglish.io/the-essentials-of-a-react-application-architecture-fe06f8d6aecd. [Accessed: 04-May-2021]
- [3]A. Joshi, “A better way to strcture react projects,” 2021 [Online]. Available at: https://www.freecodecamp.org/news/a-better-way-to-structure-react-projects. [Accessed: 09-Feb-2021]
- [4]A. Cockburn, “Hexagonal architecture,” 2012 [Online]. Available at: https://alistair.cockburn.us/hexagonal-architecture. [Accessed: 13-Aug-2012]
- [5]R. C. Martin, “Clean Architecture A Craftsman’s Guide To Software Structure And Design,” 2017 [Online]. Available at: https://archive.org/details/CleanArchitecture/page/n179/mode/2up. [Accessed: 2020-Jun-11AD]
Table of contents
Got a question?
If you have question or feedback, don't think twice and click here to leave a comment. Just want to support me? Buy me a coffee!