React.js + Redux + Next.js + TypeScript boilerplate
This is the template for React applications.
In the src dir you will find a complete example on how this system could work. You can add or remove the files you need.
If you are using the Visual Studio Code as your code editor (recommended, you can get it here), you should install and use the associated plugins.
We use Next.js due to different advantages:
Read the docs: Next.js docs
As a JavaScript superset. All the files should be written in TypeScript in order to make the code cleaner. Its configuration is set in the .tsconfig file. You can read how to configure it here.
Read the docs: Typescript docs.
For state management. With Redux Toolkit (official recommended approach for writing Redux logic), which wraps around the Redux core, and contains packages and functions that are essential for building a Redux app.
Read the docs: Redux docs, Redux Toolkit docs, React Redux docs.
For code styling. It ensures you are using the best practices and all the developers are following the same guides. The configuration is set in the .eslintrc file. You can read how to configure it here.
We use the AirBnb style guide for coding: Guide docs.
Read the docs: ESLint docs.
VSCode plugin: here.
For CSS and SCSS code styling, just like ESLint but for styles. Its configuration can be found in .stylelintrc.json. You can read how to configure it here.
We use the AirBnb style guide for coding: Guide docs.
Read the docs: Stylelint docs.
VSCode plugin: here.
It’s an opinionated code formatter used for making the code prettier. Also, by this way all the developers will be following the same style guides. It’s configured in the .prettierrc file. You can read how to configure it here.
It’s recommended to set formatOnSave to true in your Code Editor to make this step easier.
Read the docs: Prettier docs.
VSCode plugin: here.
For unit testing it uses Jest. It will look for all the files which their names finishes with “.test.ts” in the “/tests” dir and execute them. Jest is a very powerful tool for testing. Its configuration is set in the jestconfig.json file. You can read how to configure it here.
Read the docs: Jest docs.
It uses husky to add a hook to git, so it runs eslint and prettier before commiting every time.
To develop a frontend this template follows many code rules: ESLint, Stylelint, Prettier, the AirBnb guide, TypeScript, etc. But this is just for coding. The app design is harder, because we cannot have automated tools and we have to be very thoughtfull as we develop. Accessibility, performance and SEO are also issues to consider.
Before starting to develop is necessary to execute the npm run prepare
command, because it installs the husky.
Here are the guides and recommendations we want to follow to build:
You will find the template has some examples on how it could be used. You can delete the files or modify them to your needs.
The application starts at /src/index.tsx. Here the ReactDOM render method is imported and renders the entire React application in a div tag with an id called root. Also whitin the App component, Redux Provider component is rendered to have the global state available throughout the entire application.
Constants will have configuration inside the app (mainly things that are used in many places, but they won’t be modified from outside, like an specific route).
Note: Some dependencies added in package.json, specially UI libraries, are not necessary. You can remove them if you want.
The /types dir contains all the different types that could be reused in different parts of the application. For example, you might find a type that will be needed in state, controller and views layers. Also, you could find different files inside the same layer that use this type. It’s not a good practice to rewrite this type in every file (if you have to modify something, you will have to do it in a lot of files), so it’s better to have them in a specific dir.
Some guides:
In a Frontend application, errors are usually not from the application, but from what an API call can return. For this, we recommend using an AxiosHelper for error handling. Then, you should develop the way the UI displays them.
If the app will be needed in more than one language, this directory comes to the rescue.
Every app description or string that will be seen by the final user should be here. This way, you will find every text in the same place.
Also, internationalization lets you use more than one language. You can specify the description in english and spanish, for example, and also can be extended in the future.
So:
This layer works as a module to interact with the global application state. For state management we use Redux, specifically with Redux Toolkit, which is a much simpler way of writing Redux logic.
Basically Redux Toolkit avoids separating Actions and Reducers, putting them together in a single place called Slices and another advantages such as allowing state mutability in reducers, a replacement of the createStore function, etc.
This layer should never be accessed directly. If any part of the app needs to update the state, it should access it through the actions layer.
The /state directory contains three main parts:
Also, you will see two files:
For Redux Toolkit usage we recommend to read the official documentation. Is good to know that any application feature that needs to be in the global state, is necessary add a representative-name file into a /features folder, where a Slice must be created that includes the name of the feature, the initial state and the corresponding reducers. Then the feature selector, all the actions and reducer should be exported.
To subscribe a component to a part of the application state, you must pass the feature selector as a parameter to the React-Redux useSelector hook. Then when the state is updated the view will also do it and vice versa.
Note: It is important to note that non-serializable values should not be put in State or Actions. Read more.
We recommend to read the Redux best practices post.
All React components should be here only, not anywhere else. Inside the index.tsx file in this folder there must be the necessary React-Router components with their respective screens, which brings us to the /screens folder. Inside this you must put the different TSX files for each application screen.
The /components folder contains all the application components. The best way to organize the components is to create a folder with the representative name of the component with Upper Camel Case as the naming convention. Inside each folder there should be an index.tsx file which contains the React component and an index.scss file which contains the component styles. For example, for a component called Counter, in another component or view it is imported as ~/views/components/Counter, which makes the import more readable and less repetitive.
Note: It is important to note that everything related to React must only be in the /views folder, nowhere else.
There are many React form libraries. You will notice that in this template we have used Formik, which is one of them, but we also recommend the use of React Hook Form. Both are similar, having components necessary to build solid and easy-to-validate forms, also allowing the use of UI libraries such as Material-UI being completely independent of them.
For styling we decided to use SASS as a CSS Preprocessor. Inside the /scss folder should be CSS utils and variables like font sizes, media query values, colors, etc. that are needed in different parts of the application styles.
This layer has the app bussiness logic. Whatever the app needs to do or execute, it should be done here. This is the intermediate between state layer and views layer.
This is in order to prevent the state being accessed without control. Also, if in the future you need to add some bussiness logic rule, it can be added here (which is much tidier than inserting bussiness logic things in state layer).
Guide:
This directory contains all the services consumed such as external APIs or backend application.
By default, any request to other server or another service should be here.
This template have a sample on how to use other services and also how to use this one, with this template response format. It works using the axios package.
const APIClient = axios.create({
baseURL: 'HERE THE URL'
timeout: 10000,
headers: {
'X-API-KEY': 'SOME API KEY',
},
params: {
some_param: 'SOME PARAM',
},
});
Also, in /utils dir you can find a file called “axiosHelper” which will help you handling axios responses.
Axios is an awesome library but:
The file “axiosHelper” will help you get the response with the different information you need in this format, regardless of the status code:
type axiosResponse = {
success: true;
statusCode: number;
payload: any;
};
type axiosError = {
success: false;
error: {
message: string;
code?: number;
url?: string;
method?: string;
};
};
From now on, you can get the format you want like this:
/**
* Gets something.
*/
async getSomething(): Promise<axiosResponse | axiosError> {
const url = '/something';
let result;
try {
const response = await APIClient.get(url);
result = axiosHelper.handleResponse(response);
} catch (error) {
result = axiosHelper.handleError(error);
}
return result;
}
};
In both cases, if the response is valid (a JSON), it will return the object with that information.
It’s very important to add tests in order to know the application is working correctly.
We will use Jest for that. It contains an extensive documentation on how to do it: docs. Also for React components tests, we use React Testing Library.
If we have time, it’s always a good practice to have unit testing for everything.
All the tests are in the /tests directory with the suffix “test.ts”. If they don’t say “.test”, they are not tested by Jest.
Before any test, Jest will use the “prepareTests.js” script.
Unit testing is very simple when you have modules you want to test and they always return the same output.
We should do unit testing for every module or script that do not use third party dependencies or other services.
The process is very simple and you can follow Jest documentation.
test('Fs returns text OK.', () => {
const text = fs.readFileSync(FILE_PATH, { encoding: 'utf8' });
expect(text).toBe('Content of the file');
});
Always remember:
This documentation has nice good practices (for C#, but they also apply for JavaScript): docs,
We use two main tools to document the application: Jest HTML reporter for tests and TYPE DOC for code documentation.
This template will generate two different folders for documentation in different times inside /docs.
We use Jest HTML Reporter for document unit testing.
Just do unit and integration testings and it will save the results in the specified file.
We use TypeDoc. This documentation is done by using “npm run generate-docs”. It reads file by file and generates a new documentation in “/docs”. But in order to be tidy there must be some considerations:
/**
* @packageDocumentation
* @module Path/To/Module
* Here some module description that will be seen in the docs.
*/
/**
* @packageDocumentation
* @hidden
* Here some module description.
*/
/**
* Adds the sample to the database.
* @param sample Sample to save.
*/
async addSample(sample: sampleType): Promise<boolean> {
return samples.add(sample);
}
class ExampleClass {
/**
* Some property of the class.
*/
_property: string = '';
}
Note: It’s a good practice to watch documentation often, so you will see what the output is.
This template is written in TypeScript, which means it has to be compiled before running.
There’s a tool that hot reloads the new code and compiles the modified files in real time, so you don’t have to wait for an entire compilation before developing new things. This template uses a package calles “tsc-watch”, which uses tsc with “watch” mode.
When running “npm run dev”, the package basically gets the webpack dev server up and allows access through the same device with which it’s being used to develop and any other device that is connected to the same network.
This way, it’s possible to change code in the TypeScript files and see the changes in real time.
But, this system is not perfect, and it can fail in some scenarios, in which you should run “npm run dev” again:
Following the OWASP guidelines, it is not recommended to store access tokens or any sensitive information in LocalStorage or SessionStorage, mainly because they are accessible through JavaScript by XSS attack.
Here are some recommendations from OWASP and a Medium post that explain why you should store access tokens and sensitive information in cookies with httpOnly flag instead of LocalStorage/SessionStorage.
You can use the following commands:
| Command | Description |
| ————————————- | ———————————————————————————————————————————————————————————————— |
| npm run prepare | Installs the husky. |
| npm run _clean | Deletes the .next, out and build dirs. |
| npm run _control | Runs linters, formatter, type checker, unit tests and audits the production packages |
| rpm run lint | Runs eslint and stylelint in the src directory. |
| npm run format | Runs prettier in the src directory. |
| npm run type-check | Checks types. |
| npm run test:unit | Runs Jest for all the test in the /tests/unit directory. |
| npm run test:integration | Runs Jest for all the test in the /tests/integration directory. |
| npm run dev | Gets the Next.js dev server up. |
| npm run build-stats | Builds the project with bundles analyzer enabled. |
| npm run build | Runs npm run _clean and generates the production build. |
| npm run export | Exports the app to static HTML to the out dir. |
| npm start | Gets the Next.js production server up. |