Preparing a CRA based React Redux Scaffold (Part 1)

A React App. development can be started by choosing one of many available scaffolds, which offers a variety of advantages and flexibility over one another. Create React App. (CRA) is a React scaffold offered by Facebook, that provides a minimal startup boilerplate with lots of flexibility via built in scripts. It attempts to represent a clean and minimal development environment to the developer, by abstracting away many development dependencies (e.g. webpack), while exposing them when they are needed. It also supports a one way full control handover strategy called eject, that exposes all the development dependencies to the user, so that those can be customized as needed.

While considering React App development, different development stack comes in mind, including REST app stact, GraphQL app stack, and more. These stacks have their own ecosysystem with unique dependency requirements. CRA, while being a great starting point for a wide range of projects, it doesn't provide any stack specific boilerplates, and leaves it to the developer's hand. This often leaves a developer to work with stack specific boilerplate developement task, which must be completed before even starting project specific tasks.

In this article, we'll go through a REST based app boilerplate developement phases, which includes React Router, Redux, i18n, persistent state management and more. We'll also discuss briefly about dependency selection, utilization, advantages and their associated drawbacks.

First of all, we need to generate CRA boilerplate codes to get started. Before staring with any of the project work, we need node to be installed in our development machine. To install the dependency package, please follow the instructions here if a package manager is available for your system, else follow these instructions as applies to your system.

Once, Node is installed, generate a CRA boilerplate by running,

$ npx create-react-app my-app
$ cd my-app
$ npm start

This will create a my-app directory with the boilerplate codes, which has the following structure.

The first command npx create-react-app my-app fetches create-react-app package and executes it with my-app argument. This creates a directory my-app, generates all the project specific boilerplate codes in there and installs project dependency packages (specified in package.json), which creates node_modules directory.

Since we cded into the project root and run a npm start, the project starts running at localhost at port 3000 or any available consecutive port.

Now that we have our project base ready, let's get to know the primary structure.

Different phases of development requires different support packages. For now, let's install Lodash, which is a utility library that provides functions which are convenient in terms of modularity and performance.

A Redux store optionally accepts an initial state, middlewares and enhancers. We already have a root reducer. An initial state can be marked as empty using an empty object {}. But, later we'll leverage this feature to load data from persistent storage. Middleware and enhancers can be considered as addons for Redux store. As an example, Redux Thunk provides asynchronicity to dispatch Redux actions.

Redux actions are plain JS objects, where action creators are just functions that returns actions. But, when asynchronus flow (e.g. API call, scheduled interrupt) is considered, it requires its own strategy. Redux Thunk provides the capability to integrate asynchronicity to Redux's action dispatching mechanism. We'll integrate Thunk support by adding the following package.

Switch renders the first route component that matches the current path. If no path is matched, the last route component <Route component={NotFound} /> gets rendered. Notice that this component does not have a path property defined. When this is the case, the associated component will be rendered always.

This is a very basic routing flow. We are still missing layout and authenticity based routing and redirection. We'll cover it shortly.

But, for now it is important to note that, due to compatibility issue with Redux, React Router requires that every container componet should be wrapped in withRouter HOC, as follows.

Setting an Environment Variable

An environment variable can be set by creating a file named .env* (e.g. .env.local). And, putting environment variables in the following format.

REACT_APP_ORIGIN_API_PREFIX='/v1'
REACT_APP_ORIGIN_FRONTEND_PREFIX=''

The default .gitignore setup of CRA ignores several .env* prefixed files. Since these files store local configurations, a .env.example can be added with sample configurations to the SCM.

Reading an Environment Variable

Environment variables can be read using the following format.

process.env.REACT_ORIGIN_API_PREFIX

It's important to note that the variables are parsed and replaced by their corresponding value during compilation time. Also, the variables that are prefixed only with REACT_APP_, are available.

Path Alias Support

When using CRA without ejecting, webpack alias feature does not become available. While by ejecting, configuration management becomes totally manual, there's a way to get limited support for path alias, by using NODE_PATH variable as follows.

NODE_PATH=src

This enables us to import using,

import App from'containers/app';

instead of,

import App from'./containers/app';

This acts exactly like webpack alias, except the support is limited to relative directories only.

So far, we setup a CRA boilerplate, and added basic support for React, Redux and React Router. We also introduced environment variables to our setup. While this should be enough to get a basic project started, we are going to introduce a number of advanced features to our scaffold in the uncoming installment of this article. Till then, happy coding.