Towards a reactjs folder structure based on intent

Last updated Feb 20, 2023 Published Jan 18, 2021

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 aim to favor:

  • intent
  • communication

Both of them are connected somehow and in this post, I am going to address the issue that is to organizing reactjs components in a “meaningful” way, given that the official reactjs documentation does not provide an official file structure [1].

Even though 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 in her talk, arguing that front-end applications have a different directory structure every day.

The default

React create app (RCA) comes with no opinion on how you should structure your components. It is an unofficial approach to create a folder named components and use 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 provide any kind of guidance on structuring the folders by default, I assume that this is on purpose, and the reactjs team doesn’t care about it. Therefore, it opens a wide range of options, for use, developers to create such a structure.

It has 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.

There are attempts to structure reactjs applications in an 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 are key players 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 is 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. The moment is an example of a third-party library that falls into 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 using 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 requires 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 to different frameworks or libraries, it is not coupled to reactjs. As such, further analysis is required to investigate the fit for other popular frameworks.

References

  1. [1]Reactjs, “File Structure,” 2021 [Online]. Available at: https://reactjs.org/docs/faq-structure.html. [Accessed: 09-Feb-2021]
  2. [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. [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. [4]A. Cockburn, “Hexagonal architecture,” 2012 [Online]. Available at: https://alistair.cockburn.us/hexagonal-architecture. [Accessed: 13-Aug-2012]
  5. [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]