A Complete Guideline to Creating a Modern React App With TypeScript From Scratch

Going inside any framework has two benefits. It makes you a better developer and improves your understanding of the job that you are doing.

It also helps you appreciate the things that these frameworks do under the hood that we take for granted.

I wanted to go deep inside React to see how an application really works under the hood by replicating it locally.

Today, I will take you with me on this journey. I will try to keep the concepts beginner-friendly for you. You don’t need to code with me. But if you do, that will be awesome!

Let’s begin.

UPDATE (November 27, 2021)

I have updated the article with the latest version of the webpack. which is currently on 5.64.4 and webpack-cli is on 4.9.1 .

Initialize a Project

First, create an empty folder anywhere on your machine.

mkdir react-from-scratch

Initialize the Project With Yarn

Then initialize an npm project by running the following command (yarn recommended).

yarn init

or

npm init

Here is what my output looks like with yarn.

yarn init command

Primary Setup

Then we will create two folders. src is to keep our project files, and build will be used to keep the bundle files (we get these after building the project).

mkdir src build

Inside the src folder, create a index.html file. This is the only HTML file inside our project. This is why our application will be called a single-page application (SPA).

cd src
touch index.html

The contents of our index.html are as follows:

<!DOCTYPE html>
<html lang="en">
  <head>
      <meta charset="UTF-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>React From Scratch</title>
  </head>
  
  <body>
      <div id="root"></div>
  </body>
</html>

The only thing to notice is the div tag with the id="root" . This is the div that our application will connect later.

Install React

Okay, now we will install React and ReactDOM as a dependency because it will be very hard to create a React application without the React library itself :P

yarn add react react-dom

You may ask what react-dom is doing here. Well, according to extensive research (i.e., a Google search):

“The react-dom package provides DOM-specific methods that can be used at the top level of your app and as an escape hatch to get outside of the React model if you need to” — ReactDOM documentation

That means react-dom acts as a middleman between DOM and React.

Create Index File

Now create a new file named index.tsx inside the src folder.

touch index.tsx

Use the render method from the react-dom library to connect your index.html file’s content to your application.

import React from 'react';
import ReactDOM from 'react-dom';

ReactDOM.render( 
  <div> This is a new react app</div>, 
  document.getElementById('root')
);

This render method takes two things as input:

  • A jsx component (for now, the normal div)

  • A real element from dom (our div with id="root” that we added previously in our index.html)

Pretty simple. But we haven’t added TypeScript yet. Let’s do that!

Install TypeScript

Let’s now set up our TypeScript dependencies because modern React applications should be built with TypeScript.

yarn add -D typescript [@types/react](http://twitter.com/types/react) [@types/react-dom](http://twitter.com/types/react-dom)

Configure TypeScript

Now let’s create a new file named tsconfig.jsonin the projects root directory (outside src).

touch tsconfig.json

Add the following content:

{
    "compilerOptions": {
      "target": "ES5" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */,
      "module": "ESNext" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */,
      "moduleResolution": "node" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ /* Type declaration files to be included in compilation. */,
      "lib": [
        "DOM",
        "ESNext"
      ] /* Specify library files to be included in the compilation. */,
      "jsx": "react-jsx" /* Specify JSX code generation: 'preserve', 'react-native', 'react' or 'react-jsx'. */,
      "noEmit": true /* Do not emit outputs. */,
      "isolatedModules": true /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */,
      "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */,
      "strict": true /* Enable all strict type-checking options. */,
      "skipLibCheck": true /* Skip type checking of declaration files. */,
      "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */,
      "resolveJsonModule": true,
      "allowJs": true /* Allow javascript files to be compiled. Useful when migrating JS to TS */,
      "checkJs": true /* Report errors in .js files. Works in tandem with allowJs. */,
    },
    "include": ["src/**/*"],
    "exclude": ["node_modules", "build"] // *** The files to not type check ***
  }

Comments in this file explain what each of the options does. You may want to tweak little things here and there to satisfy your needs.

Install Babel

Now we need to install Babel into our project. That’s because our browsers don’t understand anything but JavaScript, so if we want our browsers to understand our jsx or tsx- files, we need some compiler.

Babel will do that for us. Let’s install some dependencies:

yarn add --dev \
  @babel/core \
  @babel/cli \
  @babel/preset-env \
  @babel/preset-typescript \
  @babel/preset-react

Explanation

The first three libraries are needed by default. We need preset-typescript for compiling TypeScript and preset-react for compiling our React-specific files.

If we want additional support for async/awaits, we will need to add two additional libraries.

yarn add -D \
 @babel/runtime \
 @babel/plugin-transform-runtime

These will help to compile async/await syntax, which is a must at this point.

Configure Babel

We will create a new file named .babelrc in the project's root folder.

touch .babelrc

Add the following configuration there.

{
    "presets": [
        "@babel/preset-env",
        [
            "@babel/preset-react",
            {
                "runtime": "automatic"
            }
        ],
        "@babel/preset-typescript"
    ],
    "plugins": [
        [
            "@babel/plugin-transform-runtime",
            {
                "regenerator": true
            }
        ]
    ]
}

Install webpack

To get webpack working, we will need to install some dependencies.

yarn add --dev \
    webpack \
    webpack-cli \
    webpack-dev-server \
    style-loader \
    css-loader \
    babel-loader \
    html-webpack-plugin \
    clean-webpack-plugin

Configure webpack

Then create a new file named webpack.config.js in the root folder.

touch webpack.config.js

Add the following content there.

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

module.exports = {
    entry: path.resolve(__dirname, 'src', 'index.tsx'),
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'bundle.js',
    },
    mode: 'development',
    module: {
        rules: [
            {
                test: /\.[jt]sx?$/,
                use: ['babel-loader'],
                exclude: /node_modules/,
            },
            {
                test: /\.css$/,
                use: ['style-loader', 'css-loader'],
            },
            {
                test: /\.scss$/,
                use: ['style-loader', 'css-loader', 'sass-loader'],
            },
            {
                test: /\.(?:ico|gif|png|jpg|jpeg)$/i,
                type: 'asset/resource',
            },
            {
                test: /\.(woff(2)?|eot|ttf|otf|svg|)$/,
                type: 'asset/inline',
            },
        ],
    },
    resolve: {
        extensions: ['.tsx', '.ts', '.js', '.jsx'],
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: path.resolve(__dirname, './src/index.html'),
        }),
        new CleanWebpackPlugin(),
    ],
    devServer: {
        static: path.join(__dirname, './src'),
        port: 3001,
        hot: 'only',
        compress: true,
        open: true,
    },
};

Quite confusing? Not really. If you are familiar with webpack, then this configuration should make sense.

If you want to learn more about the explanation of this setup, you can refer to the following article. We won't go into details here for now.

6 Webpack Concepts for Advanced React Developers Concepts to help you understand React from the inside betterprogramming.pub

Add Script

Now go into the package.json file and add the following script for starting the application.

"scripts": {
  "start": "webpack serve --config webpack.config.js --env env=development",
  "build": "webpack --config webpack.config.js --env env=production"
},

Open a terminal and run the following command:

yarn start

You should be greeted with the application running on your browser.

App Running

Similarly, if you want to build for production, you can run

yarn build

Congratulations! You have successfully set up a React application on your own. But if you are interested in good standards, here are bonus sections.

Install Prettier

Install the following dependencies for Prettier.

yarn add -D
  prettier \
  eslint-config-prettier \
  eslint-plugin-prettier

Configure Prettier

Create a file named .prettierrc.js inside the root folder.

touch .prettierrc.js

Add the following content:

module.exports = {
    semi: true,
    trailingComma: 'all',
    jsxSingleQuote: false,
    singleQuote: true,
    printWidth: 120,
    tabWidth: 4,
};

Install ESLint

To install ESLint, first, install the following dependencies:

yarn add -D \
  eslint \
  eslint-plugin-react \
  eslint-plugin-react-hooks \
  @typescript-eslint/parser \
  @typescript-eslint/eslint-plugin \
  eslint-plugin-jsx-a11y \
  eslint-plugin-import \

Configure ESLint

Then add a file named .eslintrc.js inside the root folder.

touch .eslintrc.js

Add the following contents.

module.exports = {
    parser: '@typescript-eslint/parser',
    parserOptions: {
        ecmaVersion: 2020,
        sourceType: 'module',
        ecmaFeatures: {
            jsx: true, // Allows for the parsing of JSX
        },
    },
    settings: {
        react: {
            version: 'detect',
        },
    },
    extends: [
        'plugin:react/recommended',
        'plugin:react-hooks/recommended',
        'plugin:@typescript-eslint/recommended',
        'plugin:import/errors',
        'plugin:import/warnings',
        'plugin:import/typescript',
        'plugin:jsx-a11y/recommended',
        'plugin:prettier/recommended', //should be at the last
    ],
    rules: {
        'no-unused-vars': 'off',
        '@typescript-eslint/no-unused-vars': ['error'],
        '@typescript-eslint/no-var-requires': 'off',
        'react-hooks/rules-of-hooks': 'error',
        'react-hooks/exhaustive-deps': 'warn',
        'react/prop-types': 'off',
        'react/jsx-uses-react': 'off',
        'react/react-in-jsx-scope': 'off',
        '@typescript-eslint/explicit-module-boundary-types': 'off',
    },
};

Script for Linter and Prettier

Now add two more scripts to run Prettier and ESlint.

 "scripts": {
    "start": "webpack serve --config webpack/webpack.config.js --env env=dev",
    "build": "webpack --config webpack/webpack.config.js --env env=prod",
    "lint": "eslint --fix \"./src/**/*.{js,jsx,ts,tsx,json}\"",
    "format": "prettier --write \"./src/**/*.{js,jsx,ts,tsx,json,css,scss,md}\""
},

That’s it. Now you have a fully functioning React application with TypeScript. Here is the repository.

Mohammad-Faisal/react-typescript-template-from-scratch Contribute to Mohammad-Faisal/react-typescript-template-from-scratch development by creating an account on GitHub. github.com

Imagine how many things are being made easy for us by create-react-app. I hope you learned a thing or two from this article.

Have a great day! :D

Resources

Building a Modern React App From Scratch in 2021 by Yakko Majuri

Get in touch with me via LinkedIn .


Share this post


Read more articles...

team

Create a Express Boilerplate with Typescript

team

Dockerize a Express-Typescript Application

team

Upload files to Google Drive With React+NodeJS

team

Setup Eslint Prettier and Husky in NodeJS

team

Scrape Website with NodeJS

Profile Image

Who I am

Hi, I amMohammad Faisal, A full-stack software engineer @Cruise , working remotely from a small but beautiful country named Bangladesh.

I am most experienced inReactJS,NodeJS andAWS

Buy Me a Coffee Widget