React app with Typescript and custom Webpack config

Evheniy Bystrov
9 min readDec 1, 2021

--

For now it’s popular to start a new React project using Create React App (CRA). But the main problem is configuring webpack plugins and loaders in development process. In this article I’ll describe how easy to make it manually.

Before start, I’m going to add some comments about node.js installation (can be useful for beginners).

To install node.js you can use documentation from https://nodejs.org/uk/. But it’s better to use Node version manager (NVM).

To install or update nvm, you should run the install script. To do that, you may either download and run the script manually, or use the following cURL or Wget command:

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash

Or

wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash

Then try to use it:

If you have any errors, please make other steps from the documentation.

Next, we should install node.js.

Now LTS version is 16 and it has own name: Gallium. To install it using NVM just run:

nvm install lts/gallium

Then check installed version:

Next, we need to install some packages useful for us:

npm i -g npm

It helps to use latest NPM version.

And we need Typescript with ts-node:

npm i -g ts-node typescript

For now we are done. Let’s continue with React.

If we compare custom ts/webpack configs with CRA, we need to know how to use CRA and what it gives us.

To install CRA run:

npm i -g create-react-app

Then we can create a new React project using CRA:

create-react-app cra --use-npm --template typescript

This command creates a new React project with npm and Typescript in cra directory. Don’t forget to change directory after finishing: “cd cra”.

When the process is finished we should see command to run the project. For example “npm start” command helps us to start development process.

And we will see the result in a browser tab:

When we need to build static files to release our project on production we need to run “npm run build”:

To test our project with Jest run “npm test”:

And last important command: “npm run eject” helps us to eject webpack config to manage it by ourself.

After that you can see that your package.json file was changed. If you open it you can see many new dependencies like webpack, its loaders…

And here I see the main problem — it’s old. If we need to add a new plugin or loader we need to find version compatible with webpack 4.

And this is the main problem why I created this article.

Next I show how easy to setup it from the scratch and to know what do you have in your code as a dependency, how to use it and how to update / replace it.

Who wants to see this code before reading the article I put it to a github repository: https://github.com/evheniy/react-webpack-typescript.

Just clone it and run commands from README.md file.

mkdir project
cd project
git clone git@github.com:evheniy/react-webpack-typescript.git .
npm ci
npm start

I’ll start from creating a new directory:

And creating a new empty node project:

npm init -f

It creates a new package.json file.

Now we can add a new dependencies / commands… You can read more about this file in the documentation.

Next I propose to switch from the command line to IDE. I like to use Visual Studio Code as a default IDE for development.

Any new project should have documentation, for that I’m going to create README.md file:

# The Project## InstallationTo install node.js using NVM run:```bash
nvm install
nvm use
```
Then install all dependencies:```bash
npm ci
```
## Using### DevelopmentTo run the project in development mode:```bash
npm start
```
### ProductionTo build the project for production:```bash
npm run build
```
### TestingTo run tests:```bash
npm test
```

Next our step: EditorConfig. It helps to have the same editor settings for each developer.

To use it just create .editorconfig file:

# EditorConfig is awesome: http://EditorConfig.org# top-most EditorConfig file
root = true
# Unix-style newlines with a newline ending every file
[*]
end_of_line = lf
insert_final_newline = true
# Set default charse
charset = utf-8
# 2 space indentation
indent_style = space
indent_size = 2
quote_type=single
max_line_length=120

Then we need to create .nvmrc file. It helps to use the same node.js version always:

lts/fermium

Now it’s time to setup typescript:

tsc --init

We can see that this command created a new tsconfig.json file

I think it’s better to save config in own directory. I’ll create config/ts directory and put this file as a base.json:

mkdir -p config/ts
mv tsconfig.json config/ts/base.json

Don’t forget to add typescript to the project:

npm i ts-node typescript

After that we need to create a new tsconfig.json file in root of the project:

{
"extends": "./config/ts/base.json",
"compilerOptions": {
"declaration": false
},
"include": [
"src",
"webpack",
"webpack.config.ts",
"jest.config.ts",
"declarations.d.ts",
],
"exclude": [
"build",
"coverage"
]
}

If you need to create a new ts config, for example for distributing your code to npmjs, you can create a new config file and extend base config.

Files from include part we will create later.

Next small step — browserlist config. It useful to keep your client browser versions in the same place. Then it will be useful for building the project by babel and postcss.

To use it just create a new file .browserslistrc

# Browsers that we support
>0.2%
# not dead
not ie <= 11
not op_mini all

Next we need to setup webpack with babel and postcss. But before we need to think about quality of the code. We can use Eslint and Jest.

To use Eslint we need to create its config file, ignore file and add dependencies.

.eslintignore

node_modules
build
coverage

.eslintrc.json

{
"root": true,
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": [
"./tsconfig.json"
]
},
"plugins": [
"@typescript-eslint",
"react-hooks"
],
"extends": [
"airbnb",
"airbnb-typescript",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended"
]
}

And add dependencies:

npm i eslint eslint-config-airbnb eslint-config-airbnb-typescript eslint-plugin-import eslint-plugin-jsx-a11y eslint-plugin-react eslint-plugin-react-hooks @typescript-eslint/eslint-plugin @typescript-eslint/parser

And Jest:

npm i jest @types/jest identity-obj-proxy

For testing of react component we will use React Test Renderer:

npm i react-test-renderer @types/react-test-renderer

Now we can init jest:

npx jest --init

Latest version of each config file you can find in github repository .

Now we need to setup webpack (we will use the latest version)with its plugins and loaders, babel, postcss

First let’s install all our dependencies one by one:

  • Nodejs types + some useful packages for npm scripts
npm i @types/node npm-run-all rimraf
  • webpack
npm i webpack @types/webpack webpack-cli webpack-dev-server @types/webpack-dev-server
  • Babel
npm i @babel/core @babel/plugin-transform-runtime @babel/polyfill @babel/preset-env @babel/preset-react @babel/preset-typescript @babel/preset-typescript @babel/runtime
  • sass
npm i sass
  • postcss
npm i postcss cssnano postcss-preset-env
  • Webpack plugins
npm i terser-webpack-plugin mini-css-extract-plugin html-webpack-plugin @types/mini-css-extract-plugin
  • Webpack loaders
npm i babel-loader css-loader file-loader image-webpack-loader postcss-loader resolve-url-loader sass-loader style-loader ts-loader
  • React
npm i react react-dom raf react-hot-loader @hot-loader/react-dom @types/react @types/react-dom

You can find each package and its description in https://www.npmjs.com/.

Webpack config files:

mkdir -p config/webpack/rules

This article is going to be very long. So next I put only screens of each file. Full configuration you can find in github.

  • config/webpack/rules/loaders.ts
  • config/webpack/rules/rules.ts
  • config/webpack/rules/index.ts
  • config/webpack/dev_server.ts
  • config/webpack/devtools.ts
  • config/webpack/plugins.ts
  • config/webpack/index.ts

And don’t forget to create webpack.config.ts file in root of the project:

Now we can setup babel (babel.config.json) and postcss (.postcssrc.json).

And another useful thing — declarations.d.ts. It helps to add declaration for dependencies and file formats.

Now it’s time to add static files and react code. We can use it from CRA example with some changes:

Last step — update package.json scripts section to work with the project:

"scripts": {
"start": "webpack serve --open",
"build": "webpack --mode production",
"test": "npm-run-all 'test:*'",
"test:lint": "npm-run-all 'lint:*'",
"test:code": "jest",
"test:build": "npm run build",
"lint:ts": "tsc --noemit",
"lint:code": "eslint . --ext .js,.jsx,.ts,.tsx",
"prebuild": "rimraf build",
"postbuild": "cp public/* build",
"pretest": "rimraf coverage"
},

Here we have steps from README.md file: start, build and test (eslint, jest, ts).

We can run each command:

  • start
  • build
  • test

So, everything works fine and you can see how easy to setup, use and manage it…

CRA is good for making small projects with React, but it’s not very well for real scalable production ready projects. For example you can add Server Side Rendering (SSR).

If you have own company and you need help with IT infrastructure, create app or even team, start using a new features like react/redux/nodejs/aws/serverless, please ping me and I can help.

--

--

Evheniy Bystrov

I can help with IT infrastructure (AWS), apps (Node.js + React) and teams.