Extensive React Boilerplate to kickstart a new frontend project
Tags: react, javascript, nextjs, frontend
Published: 2024-02-14 13:15:50

How much time do we typically spend on project setup? We're talking about configuring installed libraries and writing boilerplate code to structure and implement best practices for achieving optimal website performance. At [Brocoders](https://brocoders.com/), we often start new projects from scratch. That's why over 3 years ago, we created a [NestJS  boilerplate](https://github.com/brocoders/nestjs-boilerplate) for the backend so that we wouldn't have to spend time developing core functionality that the end user doesn't see but is crucial for developers. Over this time, the boilerplate has received 2.4k stars on GitHub and has gained significant popularity beyond our company. Now, we've decided to take it a step further and created the  [Extensive React Boilerplate](https://github.com/brocoders/extensive-react-boilerplate) for the frontend. So, in purpose to keep our best practices in project development together, avoiding familiar pitfalls and reducing development time, we've created [bc boilerplates](https://bcboilerplates.com/).

## Modules and libraries included in the boilerplate

To have server-side rendering out of the box, automatic page caching, preloading, and other speed optimizations, we use the **Next.js** framework. It extends React by adding static site generation and is a powerful tool for creating productive and SEO-friendly web applications. To ensure code reliability, performance, and readability in the boilerplate, **TypeScript** is utilized.

To prepare the website for supporting local languages and settings, we use the experienced language expert for web applications - the internationalization-framework **i18next**. It helps organize all added language versions and adapt the content of the site, menu, and messages for different languages and regional settings. We expanded it with packages to detect the user's browser language and transform resources into the server-side of i18next.

**Material-UI** is used for quickly creating interfaces without spending time writing components from scratch, such as buttons, input fields, tables, modal windows, and more. With dark mode support, the application based on the boilerplate is automatically configured to use the user's system theme.

**React Hook Form** library is integrated for form management, providing a simple and intuitive API optimized for high performance as it works with data without unnecessary re-renders of the entire form.

**"React Query"** is used for state management and data caching. It automatically optimizes queries, reducing their duplication, and supports data caching on both the client and server sides, allowing easy cache management across environments.

The **Cypress** library provides an interface for tracking and debugging tests, supporting various types of tests including unit tests, integration tests, user interface tests, and more.

**ESLint** helps to ensure that the style of the code in the project is consistent with the rules already established in the .eslintrc.json file to avoid potential problems and warn about possible errors.

## Architecture of the react boilerplate project and folder structure

The project structure allows for easy navigation and editing of various parts of the application. Automated tests are located in the _/cypress_ folder, divided into different specifications for testing various aspects of the application. All source code of the project, following the logical structure of the application, is concentrated in the _/src_ folder. Nested within it, the _/app_ folder displays various application pages, such as the administrative panel with pages for creating and editing users, email confirmation pages, password reset, password change, user profile, login, and registration.The _/components_ folder contains common components that can be used on different pages of the application. The services section is responsible for interacting with the API server, its files contain modules that are important for proper functionality and interaction with the backend and external services.

![File structure of the boilerplate](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y6wwx6a1t4o6daazfryj.png)

As far as this boilerplate uses Next.js framework for building React applications, the folders are used as routes. This means the more folders you add to your app folder, the more routes you will get. Additionally, if you create a new folder inside of another folder, you will get nested routes. To better understand these concepts, we suggest looking at the image below.

![Visual explanation of route formation for the project](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q6x2u80ngxyuwenvigvv.png)

We use dynamic segments in routing when flexible routes are needed. Within the file structure in the _/app_ folder, such routes wrap the folder name in square brackets. Thus, it is easy to guess that the variable segments in the route _src/app/[language]/admin-panel/users/edit/[id]/_ will be _language_ and _id_.

## Mechanisms of authentication and user interaction

Since the web application supports internationalization, additional middleware is added to each page to determine the language, so the language of the authentication form will be displayed depending on the basic system settings of the user's device. 

![The Sign In page of React Boilerplate](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g93hjk1tc327kqwdn84m.png)

### Sign Up page

The Sign Up page contains a registration form with fields for user registration, as well as the option to register via Google and Facebook. The necessary API for requests to the server to create a new account is specified, and saving user data is implemented using a context.

```typescript
export function useAuthGoogleLoginService() {
 const fetchBase = useFetchBase();

 return useCallback(
   (data: AuthGoogleLoginRequest) => {
     return fetchBase(`${API_URL}/v1/auth/google/login`, {
       method: "POST",
       body: JSON.stringify(data),
     }).then(wrapperFetchJsonResponse<AuthGoogleLoginResponse>);
   },
   [fetchBase]
 );
}
```

```typescript
export function useAuthFacebookLoginService() {
 const fetchBase = useFetchBase();

 return useCallback(
   (data: AuthFacebookLoginRequest, requestConfig?: RequestConfigType) => {
     return fetchBase(`${API_URL}/v1/auth/facebook/login`, {
       method: "POST",
       body: JSON.stringify(data),
       ...requestConfig,
     }).then(wrapperFetchJsonResponse<AuthFacebookLoginResponse>);
   },
   [fetchBase]
 );
}
```

Access and refresh tokens are acquired and stored for future requests if the backend status is ok, otherwise, error handling procedures are executed.

### Sign In page

The Sign In page contains an authentication form with fields for logging in an already registered user, and again, the option to log in via Google or Facebook. After successful authentication, the user receives an access token and a refresh token, which are stored for future requests.

```typescript
if (status === HTTP_CODES_ENUM.OK) {
     setTokensInfo({
       token: data.token,
       refreshToken: data.refreshToken,
       tokenExpires: data.tokenExpires,
     });
     setUser(data.user);
   }
```

```typescript
const setTokensInfo = useCallback(
   (tokensInfo: TokensInfo) => {
     setTokensInfoRef(tokensInfo);

     if (tokensInfo) {
       Cookies.set(AUTH_TOKEN_KEY, JSON.stringify(tokensInfo));
     } else {
       Cookies.remove(AUTH_TOKEN_KEY);
       setUser(null);
     }
   },
   [setTokensInfoRef]
 );
```

### Restore and update password

A user may forget their password, so functionality for resetting the old password by sending a link to the email is created. Of course, for such cases there should be a corresponding API on the server, like in our nestjs-boilerplate , which is perfect for for two-way interaction.

Also, there is an ability to update the password. The logic of sending an api request to the server for updating the user's password and further processing of its results is specified.

After registering a new account on the server, a link for email confirmation must be generated. Therefore, the boilerplate has logic for the confirm-email route as well.

### Public and private routes

Both public and private routes are implemented - the user's authorization is checked before displaying certain pages, and if the user is not authorized or the authorization data has not yet been loaded, the user is redirected to the sign-in page. Below is the HOC function that implements this logic:

```typescript
function withPageRequiredAuth(
 Component: FunctionComponent<PropsType>,
 options?: OptionsType
) {
 // …
 return function WithPageRequiredAuth(props: PropsType) {
   // …
   useEffect(() => {
     const check = () => {
       if (
         (user && user?.role?.id && optionRoles.includes(user?.role.id)) ||
         !isLoaded
       )
         return;

       const currentLocation = window.location.toString();
       const returnToPath =
         currentLocation.replace(new URL(currentLocation).origin, "") ||
         `/${language}`;
       const params = new URLSearchParams({
         returnTo: returnToPath,
       });

       let redirectTo = `/${language}/sign-in?${params.toString()}`;

       if (user) {
         redirectTo = `/${language}`;
       }

       router.replace(redirectTo);
     };

     check();
   }, [user, isLoaded, router, language]);

   return user && user?.role?.id && optionRoles.includes(user?.role.id) ? (
     <Component {...props} />
   ) : null;
 };
}
```

Cypress tests have been added for sign-in, sign-up and forgot-password to detect errors and check that all the functionalities of the authentication forms work on different browsers and devices.

## User’s profile management

The boilerplate includes user data pages and pages for editing their data. Functionality has been added to implement an avatar component that allows users to upload or change their profile photo. 

![The create user page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fo3xvjl9ueyui0d7xknw.png)

The _/profile/edit_ page has been created to implement the ability to edit the profile, which includes a form with personal data that the user entered during registration, such as name, surname, password, as well as adding/changing an avatar. Additionally, to ensure code quality, detect potential security issues, and verify that the profile editing functionality works properly, this part of the code is also covered by Cypress tests.

```javascript
describe("Validation and error messages", () => {
 beforeEach(() => {
   cy.visit("/sign-in");
 });
 it("Error messages should be displayed if required fields are empty", () => {
   cy.getBySel("sign-in-submit").click();
   cy.getBySel("email-error").should("be.visible");

   cy.getBySel("password-error").should("be.visible");

   cy.getBySel("email").type("useremail@gmail.com");
   cy.getBySel("email-error").should("not.exist");
   cy.getBySel("sign-in-submit").click();
   cy.getBySel("password-error").should("be.visible");

   cy.getBySel("password").type("password1");
   cy.getBySel("password-error").should("not.exist");

   cy.getBySel("email").clear();
   cy.getBySel("email-error").should("be.visible");
 });

 it("Error message should be displayed if email isn't registered in the system", () => {
   cy.intercept("POST", "/api/v1/auth/email/login").as("login");
   cy.getBySel("email").type("notexistedemail@gmail.com");
   cy.getBySel("password").type("password1");
   cy.getBySel("sign-in-submit").click();
   cy.wait("@login");
   cy.getBySel("email-error").should("be.visible");
 });
});
```

To automate the process of detecting and updating dependencies, we use the [Renovate bot](https://docs.renovatebot.com/). It helps avoid issues related to using outdated dependencies and allows controlling the dependency update process according to the project's needs.

## Conclusion

We refer to the [Extensive React Boilerplate](https://github.com/brocoders/extensive-react-boilerplate) as a structured starting point for frontend development. It pairs beautifully with our [NestJS boilerplate](https://github.com/brocoders/nestjs-boilerplate) for the backend, and with them, the development team can get started, minimizing setup time and focusing on developing unique aspects of the project, knowing that fundamentals are already correctly implemented. We also keep track of regular library updates and maintain the project in an up-to-date state. So, welcome to try our [bc boilerplates](https://bcboilerplates.com/) out :)

Full credits for this article to [Elena Vlasenko](https://github.com/ElenVlass) and the main developer of the project [Vlad Shchepotin](https://github.com/Shchepotin) 🇺🇦