A guide to building your own React stack, explaining options and tradeoffs along the way

Overview

Custom React Stack

React has a very rich ecosystem. For anything you want to do, there is probably a library or a framework available for it. That's great, but having too many options can also be very confusing. Do you want to start out simple or go for the ultimate because your app demands it? What's the right set of options for your specific use case?

This guide will help you build your own custom React stack, explaining key options and tradeoffs at each step.

Another advantage of this approach is that you will know exactly what's in your stack. When that new shiny technology comes along, you will be in a better position to slot it in.

Our Sample App: Movie Magic

For the purpose of this discussion, imagine that you want to write a movie streaming app - Movie Magic. The app should present the available movie titles and help users make a choice. It should also allow them to manage their subscriptions.

Here's a very humble beginning, just two pages:

  1. A Home page showing the list of top 10 movies:

Home Page

  1. A Settings page for users to manage their subscription:

Settings Page

Click here to test drive the final application. As you can see, it doesn't do much yet. However, this is good enough for the purpose of our discussion. Let's start by discussing our architecture choices.

Tech Stack Options

The diagram below shows the key items that make up our tech stack, along with some options. Subsequent sections will discuss the pros & cons of each option. Note that the diagram is meant to be read bottom up - imagine that we are building a stack.

Tech Stack Options

Monorepo vs. Multi-repo

For a really simple app, you can just create a single Git repo and call it a day. But what if you want to separate out reusable components into a library? Well, you can create a separate repo for it and put the compiled output in a binary repository (such as npm or Artifactory). See below. The app can pick up the library from the binary repository by adding a dependency to it. This is called a multi-repo set up (two repos in this case).

Simple Multi-Repo

Continuing this scenario, what happens when you have multiple applications and multiple libraries with complex dependencies on each other? Let's say we start adding a new repo for each application and each library. This is now starting to look ugly.

Complex Multi-Repo

Here are some issues with the multi-repo approach:

  • It is cumbersome to add new repos. You have to set up new tooling, new CI/CD pipelines, add committers, and the list goes on.
  • You start to see duplicate code in your repos because people are reluctant to put in the effort to create a new repo just to reuse code. It is much easier to copy code from another repo.
  • It is difficult to maintain consistent tooling across repos.

A solution that works better in such use cases is a monorepo.

Monorepo is a single repository containing multiple distinct projects, with well-defined relationships.

Here's an example of taking the multiple repos in the above diagram and replacing them with a single repo:

Monorepo

Here are the advantages of a monorepo:

  • No overhead to create new projects
  • Easy to refactor code for reuse
  • Consistent way of building every project
  • Bug fixes are available immediately to all dependent projects and can be tested exhaustively before committing
  • Developers can confidently contribute to any project

You can build a monorepo manually by putting all your projects into one repo and figuring out a way to organize and build them. However, people generally use an off-the-shelf monorepo platform such as Lerna, Yarn Workspaces, npm Workspaces, Turborepo or Nx.

Turborepo and Nx provide some advanced features:

  • Caching of build artifacts for faster builds
  • Parallelize builds based on dependencies
  • Build only the affected projects
  • Visualize dependency graph (this helps in avoiding cyclic dependencies)

Turborepo is my favorite because it is less opinionated - it builds on top of npm or Yarn Workspaces. This approach allows me to integrate existing templates more easily into my monorepo. Each project has its own package.json file, making it easy to track why a particular dependency was added.

Nx, on the other hand, keeps the dependencies for all projects in a single giant package.json sitting at the root. This helps maintain a single version policy. However, this has its own pros & cons (you can google for opinions). Note that Nx can be used in a bare-bones way without using Nx plugins. In this mode, Nx simply builds on top of npm or Yarn Workspaces and becomes equivalent to Turborepo.

Language

JavaScript is one of the most popular programming languages in the world. It has a huge community behind it and plenty of learning resources. For simple applications, it works really well. However, as the complexity increases it is easier to introduce bugs due to its weak type checking. If your application deals with complex data structures, it is better to switch over to TypeScript because of its static type checking. The TypeScript compiler will catch many mistakes that will simply slip by JavaScript. TypeScript is also great for defining conceptual models that are shared between backend and frontend teams.

CSR vs. SSR

Client-Side Rendering (CSR)

Client-Side Rendering

For simple applications (say with 10-20 pages) you can probably get away with a Single Page App (SPA) where all the JavaScript is loaded in one shot and thereafter all rendering takes place client-side. The client makes HTTP requests to an API server to get any data it needs to render pages. This is called Client-Side Rendering (CSR). This is also how classic React works.

CSR is simple to develop and simple to deploy (only a static bundle needs to be deployed to your web server). It's perfect for simple applications. However, the downside is that the initial render is slow because the entire JavaScript has to be downloaded before rendering can happen. In technical terms, we have a slow First Contentful Paint (FCP) and a slow Time to Interactive (TTI). If you are building a marketing or eCommerce site your users may not have the patience to wait for the app to load. If that's the case, you should consider SSR.

Server-Side Rendering (SSR)

Server-Side Rendering

In Server-Side Rendering, as the user navigates through the site, the browser makes requests to the web server to render individual pages. The web server must connect to the API server and get the data it needs to render pages. It needs to be smart to compose pages really fast and send them to the browser (unlike CSR, where the server simply sends a pre-built static bundle to the browser). This puts a lot more load on the web server. However, the advantage is that the browser sees its First Contentful Paint (FCP) really fast. The Time to Interactive (TTI) is still slow because interactions cannot start until the JavaScript is also sent to the browser (a process called hydration). That's the tradeoff.

Next.js and Remix are a two of the most popular Server-Side Rendering frameworks in the React ecosystem.

Movie Magic Tech Stack

Given the options discussed above, I decided to build Movie Magic using three different stacks to illustrate the differences: Classic React, Next.js & Remix. The chart below shows the decisions made within each stack.

Tech Stack Selection

Movie Magic Repo Structure

Repo Structure

Building Movie Magic

Development Build

npm install
npm run dev

Open browser windows at each of the following URLs to see the respective demo apps:

  1. http://localhost:3000/: Movie Magic | React
  2. http://localhost:3001/: Movie Magic | Next.js
  3. http://localhost:3002/: Movie Magic | Remix

Note that the React app fetches mock data from MSW, whereas the other two apps fetch real data from the movie-magic-api.

Note: Do not run npm install in any of the subdirectories. It will break the build. There should be only one package-lock.json file in the entire repo (at the root).

Production Build

To build all apps and packages, run the following command:

npm install
npm run build

Clean Build

Removes all build artifacts and performs a clean build.

npm run clean
npm install
npm run dev

For an "aggressive" clean build, add one more step as shown below. This wil build the lock file from scratch.

npm run clean
rm package-lock.json
npm install
npm run dev

Running Storybook

cd storybook
npm install
npm run storybook  # you can also run it from the root directory

Running Unit Tests

npm run test

Running End-to-End Tests

npm run dev # starts a local server hosting the react app

# run cypress in a different shell
npm run cypress

Code Formatting

npm run format
You might also like...
30 Days of  React challenge is a step by step guide to learn React in 30 days
30 Days of React challenge is a step by step guide to learn React in 30 days

30 Days of React challenge is a step by step guide to learn React in 30 days. It requires HTML, CSS, and JavaScript knowledge. You should be comfortable with JavaScript before you start to React. If you are not comfortable with JavaScript check out 30DaysOfJavaScript. This is a continuation of 30 Days Of JS. This challenge may take up to 100 days, follow your own pace.

React Clone - How React Works: An In-Depth Guide
React Clone - How React Works: An In-Depth Guide

Как работает React: подробное руководство Привет, друзья! В этой статье я покажу вам, с чего начинается React. Что это означает? Это означает, что мы

 Ultimate Guide to setup React Context API with our custom hook [Typescript]
Ultimate Guide to setup React Context API with our custom hook [Typescript]

Ultimate Guide to setup React Context API with our custom hook [Typescript] To start working on this project simply run the following commands git clo

repository to study react advanced guide

repository to study react advanced guide

This tutorial to guide you how to add react.js into shopify normal theme

Integrate-react.js-into-shopify-theme Tutorial to integrate the react.js into shopify theme https://prnt.sc/1w0rgx0 Step note: you have to run theme w

TSDX React w/ Storybook User Guide

TSDX React w/ Storybook User Guide Congrats! You just saved yourself hours of work by bootstrapping this project with TSDX. Let’s get you oriented wit

ReactJS Context API Guide
ReactJS Context API Guide

Context API is a mechanism for managing state. It allows you to transfer data across the component tree without having to manually feed data down each level. It prevents props from driling.

Jed Saylor minting dapp is a quick and easy way to connect your smart contract and start minting NFTs.
Jed Saylor minting dapp is a quick and easy way to connect your smart contract and start minting NFTs.

Welcome to Jed Saylor 👾 All the code in these repos was created and explained by Jed Saylor on his course. To find help please visit: 📺 Instagram Je

🔍 A package with components for building your dream command palette for your web application.
🔍 A package with components for building your dream command palette for your web application.

A command palette for React A package with components for building your dream command palette for your web application. Features Installation Example

Comments
  • Storybook does not support React 18

    Storybook does not support React 18

    Update dependencies on @storybook/react from next to the latest version when https://github.com/storybookjs/storybook/pull/17215 gets merged.

    Edit

    It is merged - will be released as part of storybook 3.5.0

    opened by nareshbhatia 0
Code examples for the blog post titled The Complete Guide to Full Stack Solana Development with React, Anchor, Rust, and Phantom

The Complete Guide to Full Stack Solana Development with React, Anchor, Rust, and Phantom Code examples to go with the blog post available here Prereq

Nader Dabit 424 Sep 27, 2022
A simple way to write re-usable features with React + EffectorA simple way to write re-usable features with React + Effector

Effector Factorio The simplest way to write re-usable features with React + Effector Install npm install effector-factorio Why this? People became to

Anton Kosykh 33 Sep 30, 2022
null 1 Apr 28, 2022
Node.js library for building systematic trading strategies in reactive way.

Node.js library for building systematic trading strategies in reactive way. Use the power of TypeScript and Reactive Programming to research, develop

null 2 Dec 22, 2021
This Project is a fork of Ethereum Boilerplate and demonstrates how you can build your own NFT Rarity Ranker.

This Project is a fork of Ethereum Boilerplate and demonstrates how you can build your own NFT Rarity Ranker.

null 86 Oct 5, 2022
Step-by-step guide on compiling C++ codes with Emscripten into wasm and using it with Webpack + Typescript + React setup

Step-by-step guide on compiling C++ codes with Emscripten into wasm and using it with Webpack + Typescript + React setup

Joel M 15 Sep 29, 2022
Write your own version of React. Why? Because you CAN!

Write your own version of React. Why? Because you CAN!

vutr 24 Sep 2, 2022
How to mint your own NFT token with react

Mint your own basic off chain NFT Description This project teaches you how to mint your own NFT token. Here are some important packages that we will b

null 6 May 17, 2022
my-watchlist is a web application for creating your own watchlist.

my-watchlist is a web application for creating your own watchlist. The website tracks your created watchlist, so that you can comeback anytime and pick from where you left.

Ashish Poudel 4 Jun 25, 2022
Crypt Eye, Your very own personal crypto currancy journal.

Crypt Eye Description Crypt Eye, Your very own personal crypto currancy journal. Patch 1.0 Features: TradingView Powered Chart Widget Stay on top of y

Pat Brown 1 Jul 8, 2022