Creating React Web App from Scratch

Setting up React Client from scratch

  1. Setting up Nodejs Express Typescript Server
  2. Setting up a custom logger for node express typescript server
  3. Setup Code Linting in VSCode for Express Typescript Server with Eslint
  4. Configuring Tooling using ESLint, Editorconfig, Prettier and Husky
  5. Setting up React Client from scratch
  6. Configuring Monorepo with yarn workspaces and lerna
  7. Creating REST APIs using Node, Express, Typescript, Mongodb

In the last tutorial we completed, setting up tooling for our node express typescript server, so let’s now focus on building our client app using react and typescript.

creating our react app base

If you are a beginner with react and don’t want to setup react manually, you can go with this command, that will create a react app with typescript support out of the box.

yarn create react-app web-client --template typescript

But, if you are like me – who likes to do stuff from scratch, this guide is for you !

So let’s get started and setup our react app from scratch.

Trick

I recently came across this trick, where all you need to create a react app without node installed in your pc. Tip – All you need is docker 🙂

docker run --rm -it -v "$(pwd):/temp" --workdir "/temp" node bash -c "npx create-react-app app --template typescript"

What this command does is it will pull in the node image and generate a react app with typescript in “app” directory, even if you no node installed in your system. Docker does the heavy lifting for you.

Setup

so let’s create our client directory inside our /app directory.

mkdir web-client
yarn init
code .

create public and src directory inside /app/web-client directory. “public” directory handles any static assets, and houses our index.html file, which react will use to render our app.

The following code was sourced from the react documentation with some very slight modifications. Feel free to copy the following HTML markup into a new file index.html inside of the public directory.

<!-- sourced from https://raw.githubusercontent.com/reactjs/reactjs.org/master/static/html/single-file-example.html -->
<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  <title>React Starter</title>
</head>

<body>
  <div id="root"></div>
  <noscript>
    You need to enable JavaScript to run this app.
  </noscript>
  <script src="../dist/bundle.js"></script>
</body>

</html>

create a .gitignore file :

node_modules
dist

So, now our HTML page is all set up, but we now need to make sure our es6 code gets compileed
properly, for that we will use babel.

Let’s install the required dependencies:

yarn add -D @babel/core @babel/cli @babel/preset-env @babel/preset-react 

babel-core is the main babel package — We need this for babel to do any transformations on our code. babel-cli allows you to compile files from the command line. preset-react and preset-env are both presets that transform specific flavors of code — in this case, the env preset allows us to transform ES6+ into more traditional javascript and the react preset does the same, but with JSX instead.

we need to create a .babelrc file to tell babel that we’re going to use the env and react presets.

{
  "presets": ["@babel/env", "@babel/preset-react"]
}

If you want to install/require more plugins that helps in transformation, you can always refer
to the docs here at for plugins : https://babeljs.io/docs/plugins/

Now we need to setup Webpack to create optimized bundle !

yarn add -D webpack webpack-cli webpack-dev-server style-loader css-loader babel-loader file-loader

Webpack uses loaders to process different types of files for bundling. It also works easily alongside the development server that we’re going to use to serve our React project in development and reload browser pages on (saved) changes to our React components. In order to utilize any of this though, we’ll need to configure Webpack to use our loaders and prepare the dev server.

Let’s create our webpack.config.js

const path = require("path");
const webpack = require("webpack");

module.exports = {
  entry: "./src/index.js",
  mode: "development",
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        exclude: /(node_modules|bower_components)/,
        loader: "babel-loader",
        options: { presets: ["@babel/env"] }
      },
      {
        test: /\.css$/,
        use: ["style-loader", "css-loader"]
      },
      {
        test: /\.(png|jpe?g|gif)$/i,
        use: [
          {
            loader: 'file-loader',
          },
        ],
      },
    ]
  },
  resolve: { extensions: ["*", ".js", ".jsx"] },
  output: {
    path: path.resolve(__dirname, "dist/"),
    publicPath: "/dist/",
    filename: "bundle.js"
  },
  devServer: {
    contentBase: path.join(__dirname, "public/"),
    port: 3000,
    publicPath: "http://localhost:3000/dist/",
    hotOnly: true
  },
  plugins: [new webpack.HotModuleReplacementPlugin()]
};

To summarize our webpack looks in to the /src/index.js in dev mode, and checks for files if its .js/jsx it will use babel-loader , if its .css files it will use style and css loader.

The bundle created by babel will be saved in /dist folder as bundle.js , we are also using devserver that can read all the assets from the public directory.

We will use webpack HotModuleReplacement plugin, so that we don’t have to refresh our browser everytime whenever we change code (Real time reload of react client). All we do for that in terms of this file is instantiate a new instance of the plugin in the plugins property and make sure that we set hotOnly to true in devServer. We still need to set up one more thing in React before HMR works, though.

setup react

Now we have setup our babel and webpack, time to start using react.

yarn add react react-dom react-hot-loader

We need to tell our react app where to hook into the DOM – in our index.html .

Let’s create a new index.js file in our src directory.

import React from "react";
import ReactDOM from "react-dom";
import App from "./App.js";
ReactDOM.render(<App />, document.getElementById("root"));

and let’s create our App component in src/App.js

import React, { Component} from "react";
import {hot} from "react-hot-loader";
import "./App.css";

class App extends Component{
  render(){
    return(
      <div className="App">
        <h1> Hello, World! </h1>
      </div>
    );
  }
}

export default hot(module)(App);

Let’s add our App.css

.App {
  margin: 1rem;
  font-family: Arial, Helvetica, sans-serif;
}

Final project structure will look something like this:

.
+-- public
| +-- index.html
+-- src
| +-- App.css
| +-- App.js
| +-- index.js
+-- .babelrc
+-- .gitignore
+-- package-lock.json
+-- package.json
+-- webpack.config.js

Now, to run the app, we can use a start script inside package.json like this to tell webpack to start the dev-server in package.json

"scripts" : {
   "build": "webpack --mode production"
   "start": "webpack-dev-server --mode development --progress"
}

That’s it all you need to do is :

yarn start

It should start the react app in watch mode, all your changes will be live-reloaded.

Scroll to Top