How to organize files and folders? How to enforce a style guide? What type system, linter and tester to use? How to maintain code quality? This post is based on the series of posts: Modernizing a jQuery frontend with React.
This post is based on the series of posts: Modernizing a jQuery frontend with React. If you want to get a better overview of the motivation for this post we recommend you first read our initial post.
Nowadays, it is very easy to set up a small React application, or to start one from scratch. Especially if you use create-react-app. Most projects probably just need a few dependencies (for example, for state management and for internationalization) and a
src folder with at least a
components folder. I guess this is how most React projects start. Typically, though, as the project grows the number of dependencies, components, reducers and other shared utilities tends to increase in a, sometimes, not so controlled manner. What do you do when it is no longer clear why some dependencies are needed or how they work together? Or when you have so many components it becomes difficult to find the one you need? What do you do when you want to find a component but you don’t really remember its name?
These are just some examples of the questions we came across while rebuilding our frontend at Karify. We knew that the number of dependencies and components was eventually going to grow out of hand. That meant we needed a plan that would be scalable enough to keep up with future development. This plan involved defining conventions for our file and folder structure, code quality and also defining the overall architecture. Most importantly, all this should be easy to pick up by new developers without requiring them to have much insight into all our dependencies and code style.
We went through multiple phases until we figured out how we wanted to organize our React frontend. Initially, we thought of placing it in the same repository as our jQuery frontend. However, the imposed folder structure of our backend framework made this option undesirable. Next, we thought of moving it into a separate repository. This worked well at first, but with time we started thinking about creating other frontends, such as a React Native frontend, which motivated the need for a component library. This led us to split this new repository into two separate repositories: one for the component library and one for the new React frontend. Even though this seemed like a good idea, it resulted in a very complex review process. The relationship between changes in the two repositories became unclear. Finally, we chose to bring them together again into one repository, but this time as a monorepo.
We chose a monorepo because we wanted to create a separation between our component library and our frontend applications. The difference between our monorepo and others out there is that we don’t really need to publish the packages inside of it. For us, the packages serve only as a means for modularity and separation of concerns. It is especially useful to have different packages for every different application since we can specify different dependencies and scripts for each one of them.
We set up our monorepo using yarn workspaces with the following configuration in our root
"workspaces": [ "app/*", "lib/*", "tool/*" ]
Now some of you might wonder why we didn’t simply use a packages folder like in other monorepos. Mainly because we wanted to create a separation between our applications and our component library. Besides that, we also knew we needed to create some tooling of our own. So, we came up with the folders you see above and here is an explanation for each one of them:
Regardless of where we place them, all our packages always have a src folder and optionally have a bin folder. The src folder of our app and lib packages might contain some of the following folders:
reduxstate or our API payloads.
This folder structure allows us to write really modular code since it creates a clear separation of concerns between different concepts defined by our dependencies. This helps with the lookup of variables, functions, or components in the repository, independently of us knowing if they exist or not. Furthermore, it also helps keeping the contents of these folders to a minimum, which in turn makes them easier to process.
One challenge with this new folder structure is to make sure we stick to it. It is tempting to start creating different folders in different packages and organizing files differently between them. While that might not always be a bad idea we would end up with a mess if we don’t do it consistently. To help with that, we created a file system linter which I’ll describe in more detail in the next section.
The best way to learn something is by doing. It works even better if it means working on something for fun. So, how about learning about React, React hooks and TypeScript by building your own meme generator? This tutorial will show you how to do it.
In this article, we are going to take a look at how we can work with IndexedDB in TypeScript while working with a React application. Let’s take a look at what is IndexedDB. IndexedDB is a low-level API for client-side storage of significant amounts of structured data, including files/blobs. This API uses indexes to enable high-performance searches of this data. While Web Storage is useful for storing smaller amounts of data, it is less useful for storing larger amounts of structured data.
In the past few years, the buzz around functional programming has been growing, but it can be challenging to apply theoretical concepts to everyday work. How can we make the code we work on more functional? What advanced patterns can you use, and why should you do that? And what do React hooks have to do with all this? In this talk we’ll have a look at real-life examples and patterns you can use to make React apps more functional.