Article thumbnail

🌟 Dream stack for React dev

15m
architecture
project setup
patterns
quality gates

Intro

It will be a longer article about project setup. Prepare a huge mug of coffee before you start reading.

Prelude

Developers should work on functionalities. Did I say something weird?

Many of you may disagree. What about creating a project? What about connecting eslint, prettier? What about preparing a test environment for unit and e2e tests? Seems like a lot of work. Honestly, it may be...

However, today you'll see how you can do it easier/better/faster/stronger 🎧.

Here is a final result. Don't be afraid, just use it :0.

1. Monorepo

We'll divide our solution into applications and libraries. All of these will be stored in a single repository with the same configuration for linting, formatting, TypeScript, jest, cypress, storybook, ...etc.

Thanks to this you will have the opportunity to run the applications separately or together. This is what you can achieve with monorepo. In simple words, it's a way of storing and managing a solution, which involves keeping the code in a single repository and dividing it into packages and applications accordingly.

2. Monorepo with nx

It's mainly a CLI and patterns that helps you to create and manage monorepo. Below is a list of cool things you will get with this technology:

  • apps and libs generation via CLI
  • organized structure
  • option to configure stuff like storybook via one command
  • dependency preview via graph
  • same configs for everything
  • configuration of the TypeScript
  • option to choose the way of styling your components
  • routing configuration
  • bundler configuration
  • unit and e2e tests configuration
  • and many more...

3. What will we create?

We are going to make a solution that will allow you to manage your blog and display the created articles/courses. So let's describe the components we'll create:

  • application for presenting the blog content and homepage
  • a blog management application
  • library for communicating with the API
  • utilities library
  • a library with components

Each component will be independent. It will reduce the risk of conflicts. Libs will be consumed by apps.

Loading

Building blocks

Check out this article if you are interested in architecture.

4. Initialization of the project

First, install this script, which will start the nx repository:

npm i -g create-nx-workspace@latest --legacy-peer-deps

Later you need to type:

npx create-nx-workspace@latest

The CLI will ask you the following questions sequentially. You can find description of the options in nx documentation. Let's focus on creating our dream project.

Answer the questions the same way I did.

Loading

Questions and answers

The file and folder structure generated by nx should look like this:

Loading

Generated content for blog application

If you look at it you will see that by default you have TypeScript, prettier and eslint configured. In addition, tests in jest have been configured and e2e in cypress.

We already have a project and app in Next.js. Now it's time for the single page application in React.

cd .\system\

npx nx g @nrwl/react:application blog-creator

The tool may ask you to install additional dependencies, which it uses to generate folders and files. Confirm it. After that, you will see similar questions as before. Answer them the same way I did:

Loading

React app done

We have the apps! After a while you'll see two new folders in the apps directory.

In this commit you have the full changes.

5. Creating libraries

The idea is the same, only the questions and your answers differ. It's beautiful ❤️. Type the command:

npx nx g @nrwl/react:lib figa-ui

I named my components library after my beloved cat - Figa. You can name it after a turtle (or whatever pet you have at home). These are my answers:

Loading

You have figa-ui installed :D

Now it's time to do the two simplest things. We need to create two TypeScript libraries. Type the following two commands:

npx nx generate @nrwl/js:lib utils

npx nx generate @nrwl/js:lib blog-api

In both cases, choose the same answers:

Loading

TypeScript libs are cool

We have what we wanted, so let's move on.

In this commit you have the full changes.

6. Adding storybook to UI library

Storybook will be needed for our components library. Nx allows per scope configuration or global one. We need scoped. So let's enter some commands:

npm i --save @nrwl/storybook --legacy-peer-deps

npx nx g @nrwl/storybook:configuration figa-ui --uiFramework=@storybook/react

As usual there will be questions, answer as I did:

Loading

Storybook ready!

Now you can start the storybook process and play with it via this command:

npx nx run figa-ui:storybook

After a while, the storybook window will launch with the message that you don't have any story yet. We'll add the Bell.tsx and Bell.stories.tsx component to see if everything works as it should.

Loading

It works!

In this commit you have the full changes.

7. Running the applications

Now it begins :D. You can run all applications, one of them, or just the storybook. It depends what kind of feature you are already working on. To run single app type:

npx nx serve blog

You can run all apps via:

npx nx run-many --parallel --target=serve --projects=blog,blog-creator

or

npx nx run-many --target=serve --all

You can get an error about same port usage attempt. To fix it you need to visit project.json files and add port number. For each application add different one. After that type:

npx nx run-many --target=serve --all

and all applications will be run on different ports, in my case 3001 and 3002. Looks cool? Yea!

In this commit you have the full changes.

8. Using libraries

Take a look at this. Do you want to use a components library in two applications? Forget about npm install. All you need is a simple import statement.

Loading

Who cares about configuring aliases for webpack? Certainly not you :D

In this commit you have the full changes.

9. Adding custom fonts

We need to download the fonts. Lexend variant will be suitable for us so let's take it from Google Fonts in the following sizes (300, 400, 500, 700). Immediately after that, we need to place the files in the appropriate directory - our figa-ui library.

We are using styled-components so there is a need to create global styles, in which we'll declare our setup for fonts.

Loading

The current setup doesn't work yet. We need to add minor changes in the preview.js file and its extension must be changed to .tsx.

Loading

In the ts.config file, we need to add preview.tsx to include array. Errors will be displayed if we skip that.

Loading

Well, how to test it? We need a component. Below is a partial implementation of Font component and usage in various places.

Loading

At this stage, the fonts should look the same in the storybook, in the SPA application in React, and in the Next.js application.

In this commit you have the full changes.

10. Adding husky

Husky is a library that allows you to run a scripts before a specific git hook. It is usually used to check code consistency, run tests and format code before commit. Let's install it via command npm i --save-dev husky.

On this page you have a list of all hooks.

Before each commit we need to format code with prettier and perform check with eslint. Fortunately for us, nx provides the configuration of both by default so the only thing left is the husky setup. To do this, we need to define an aliases for the scripts in package.json.

Loading

Now every developer must run the prepare command after downloading the repository. Without that, husky will not work. After launching, you should see the .husky directory and the pre-commit file that needs to be changed.

Loading

Husky ready

The last change is to define the scripts that will be executed before the commit.

Loading

Now every time when someone tries to do a commit then the scripts will be executed. If you want to skip the husky because you're just checking something, then use the git commit -m "I'm just checking" --no-verify.

In this commit you have the full changes.

11. Adding themes

We want to give users the ability to set everything in the application according to their preferences. This would be useful for creating predefined themes or to debug interface behavior by developers/designers.

It may seem like overkill, but admit that it's a pretty cool feature and not difficult to implement. You just have to stick to the specific guidelines that we're about to establish. Let's start by defining the design tokens and the shape of theme.

Design tokens? These are nothing more than rigidly fixed values that our design system will use. It can be background color, font color, border rounding, font size and others... To simplify, these are nothing more than unique variables to which we assign the settings of our design system.

  • background.color='#f0f0f0'
  • font.color='#000000'
  • boxes.radius100='4px'
  • font.size100='16px'

Loading

Note the quite "strange" shape of the tokens object. This manner is taken from Material design to which I refer you in this link.

That themes should allow us to describe each component in our UI library, so we need to make sure that the values are taken from the theme, which the user is using.

Loading

When you add a new component, remember that all settings should be added to the themes, and if you use a new font size, color or anything else, you need to include it in the design tokens. Thanks to this you will get a very scalable components library. Now it's time for real work. Let's use Context API to provide logic for themes management.

Loading

Done! All that's left is to use the theme in the styles and you can enjoy the ability to set up the UI in any way you want. Now with every next component you just need to use this approach.

Loading

Let's assume that you want to use a component, and later you want to change theme. All you need to do is to wrap the whole application with the provider and import the dedicated component.

Loading

Loading

Themes showcase

In this commit you have the full changes.

12. Sharing fonts between libs and apps

If you run the application or storybook and you don't have "Lexend" fonts installed, then get ready for the error in the browser console. We added the font face and font files, but did we think to move them to the public directories for the application or indicate for the storybook where these fonts are? It seems that no...

The case for the storybook is easy. Just indicate the place from where the storybook should copy our assets and it will be done automatically during build. I moved the font files to the very top of the file and folder structure, just for convenience when importing. Next, I changed the configuration in the main.js file.

Loading

I corrected the import in font face to be shorter. The assets directory is redundant. Immediately after that, the fonts in the storybook updated their look and started to look like a real "Lexend".

Loading

Now the applications. Here is a little more work. We need to use the webpack plugin to copy the contents of one folder to another. We'll do this for both applications in Next.js and in pure React.

Loading

Loading

In this commit you have the full changes.

13. Fixing a strange error in styled-components

If you launch the console in the Next.js application, you will see an error indicating that the generated values for the className property, are different on the server and on the client. To fix it we need to add this to next.config.js.

Loading

In this commit you have the full changes.

Full example

Repository to play with.

Summary

We went through the wonderful tool together. I recommend playing with it. We have described only a part of the possibilities.

There is still place to add many more things. However, I think that it is better to add a little less than more. The repository we have implemented will be constantly improved so we recommend to taking a look at our Github from time to time.

If you enjoyed it, be sure to visit us on Linkedin where we regularly upload content from programming.

I create content regularly!

I hope you found my post interesting. If so, maybe you'll take a peek at my LinkedIn, where I publish posts daily.

Comments

Add your honest opinion about this article and help us improve the content.

created: 28-02-2023
updated: 21-04-2023