Build React Project from Scratch

Alyona Rodin
Nov 3 · 9 min read

One way quickly and without any efforts to create a React Project is create-react-app. Create-react-app will set up web app by running only one command. Make sure to have the latest version of Node.js. Run the command to check what version:

npm -v 

Install the newest npm update:

npm install npm@latest -g
  • -g means globally

npx is used to run packages without downloading. Run the commands in terminal:

npx create-react-app my-app 
cd my-app
npm start
  • my-app is a name of the folder
  • cd change directory
  • npm start runs the app in development mode. It will open http://localhost:3000

Another way to create React Project is manually. First, install npm. npm is the software registry, which allows to share, use code, and lets easy to update the shared code. npm is distributed with Node.js and is installed with Node.js.
Node.js is a JavaScript runtime built on Chrome’s V8 JavaScript engine.
Engine processes JavaScript in the browser. Another words, it compiles the JavaScript code to native machine code.


Create directories by running the following commands in terminal:

mkdir [name]
cd [name]
mkdir -p src/components src/styles
  • [name] is the name of the folder
  • mkdir creates new folder — makes directory
  • cd changes directory
  • mkdir -p src/components src/styles creates a folder src with folders styles and components (-p is path)

Additional commands:

  • pwd prints working directory
  • ls lists information about files
  • mv move or rename files or directories (mv -f [file name] [new place])

To start new Node.js project, run the command npm init to answer the following questions below or press ENTER to skip questions one by one. These questions is the starting point in the package.json.

npm init package name: (react_project)
version: (1.0.0)
description:
entry point: (index.js)
test command:
git repository:
keywords:
author:
license: (ISC)
Is this OK? (yes) ENTER
  • package name is the name of your project

To skip the questions at all just run the command with -y flag:

npm init -y

npm init command creates package.json file, which contains the skipped/answered questions.

{
"name": "react_project",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}

Install webpack. Webpack is a module bundler for Javascript applications. Programs, in modular programming, consist of discrete chunks of functionality called a module. Webpack builds a dependency graph which maps modules for project and generates one or more bundles. The situation when one file depends from another file, webpack treats this as dependency. To install webpack, run the command:

npm install webpack webpack-cli --save-dev
  • - - save-dev saves into devDependencies in package.json file. Installing webpack and webpack-cli, allows interact with webpack either from its Command Line Interface (CLI) or API. Webpack-cli is the tool to run webpack on the command line. New files were added into project, which are package-lock.json and node_modules. Package.json got ‘devDependencies’:
{ 
"name": "react_project",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
+ "devDependencies": {
+ "webpack": "^4.41.2",
+ "webpack-cli": "^3.3.10"
}
}

React is a Javascript library for creating user interfaces (UI). To install React run the commands:

npm install react 
npm install react-dom

React package contains the functionality necessary to define React components. It used usually with React renderers react-dom (web) or react-native. Package.json got ‘dependencies’:

{ 
"name": "react_project",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"devDependencies": {
"webpack": "^4.41.2",
"webpack-cli": "^3.3.10"
},
+ "dependencies": {
+ "react": "^16.11.0",
+ "react-dom": "^16.11.0"
}
}

Babel is a Javascript compiler. Install Babel by running the commands:

npm install --save-dev @babel/core babel-loader @babel/preset-env @babel/preset-react
  • @babel/core transforms ES6 code to ES5
  • @babel/cli can be used to compile files from the command line
  • babel-loader webpack helper to transpile code, given the preset. Transpiler (source-to-source compilers) is a tool which reads source code in one programming language to converts it into another language.
  • @babel/preset-env preset which helps Babel to convert ES6, ES7, ES8 code to ES5. Preset is a predetermined set of plugins. Transformations come in the form of plugins, which are small JavaScript programs that instruct Babel on how to carry out transformations to the code.
  • @babel/preset-react preset which transforms JSX to JavaScript

Package.json:

{ 
"name": "react_project",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"devDependencies": {
+ "@babel/core": "^7.6.4",
+ "@babel/preset-env": "^7.6.3",
+ "@babel/preset-react": "^7.6.3",
+ "babel-loader": "^8.0.6",
"webpack": "^4.41.2",
"webpack-cli": "^3.3.10"
},
"dependencies": {
"react": "^16.11.0",
"react-dom": "^16.11.0"
}
}

Create index.html file inside of src file [src/index.html] and add the code:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>[project name]</title>
</head>
<body>
<div id="root">
</div>
</body>
</html>
  • <meta charset=”UTF-8"> the character encoding for the HTML document and UTF-8 is the preferred encoding for e-mail and web pages.

Create index.js file inside of src file [src/index.js] and add the code:

import React from "react";
import ReactDOM from "react-dom";
import App from "./components/App.js";
ReactDOM.render(<App />, document.getElementById("root"));
  • imported react from ‘react’, react-dom(web) from ‘react-dom’, and component App.js as App [<App />]
  • document is any web page loaded in the browser, which is an entry point into the web page’s content (DOM tree). DOM — document object model.
  • document.getElementById() is a method that returns an element object representing the element whose id property matches the specified string. Id is ‘root’ matches in the index.html id in the tag <div>.
ReactDOM.render(element, container[, callback])

Create App.js file inside the src/components [src/components/App.js] and add the code:

import React, { Component } from "react"; 
import '../styles/App.css';
class App extends Component {
render() {
return (
<div>
<h1>REACT!</h1>
</div>);
}
}
export default App;

Create App.css file inside the src/styles [src/styles/App.css] and add the code:

h1 {    
color: #37474f;
text-align: center;
}

Create webpack.config.js file in the root directory. When webpack processes the application, it starts from a list of modules defined on the command line or in its config file webpack.config.js. Starting from these entry points, webpack recursively builds a dependency graph that includes every module the application needs and bundles them to be loaded by the browser. Entry points in the webpack.config.js:

module.exports = {
entry: './path/to/my/entry/file.js};

Add in webpack.config.js the code:

module.exports = {
entry: "./src/index.js",
};

Output configurations tells webpack how to write the compiled files to disk. This configuration would output a single budle.js file into the dist directory [dist/bundle.js]. In webpack.config.js add the output:

const path = require("path");module.exports = {
entry: "./src/index.js",
output: {path: path.join(__dirname, "/dist"),
filename: "bundle.js"
}
};
  • __dirname directory name of the current module, which is ‘dist’

Create .babelrc configuration file in the root directory. es2015 and react do not require configuration. Add the code below:

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

Loaders (babel-loader also) are transformations that are applied on the source code of a module. They allow to preprocess imported/ ‘loaded’ files. Loaders are evaluated/executed from right to left (or from bottom to top). To tell webpack to load a CSS file or styles, install the loaders by running a command:

npm install --save-dev css-loader style-loader

Add babel-loader, css-loader, style-loader into webpack.config.js:

const path = require("path");module.exports = {
entry: "./src/index.js",
output: {path: path.join(__dirname, "/dist"),
filename: "bundle.js"
},
module: { rules:
[{test: /\.js$/,
exclude: /node_modules/,
use: ["babel-loader"]},
{test: /\.css$/,
use: ["style-loader", "css-loader"]}
]
}
};
  • /\.css$/ is a regular expression that says test if it matches .css till end of input, use css loader and style loader
  • /\.js$/ is a regular expression that says test if it matches .js till end of input, use babel loader, and exclude node_modules

Package.json has additional devDependencies:

{ 
"name": "react_project",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.6.4",
"@babel/preset-env": "^7.6.3",
"@babel/preset-react": "^7.6.3",
"babel-loader": "^8.0.6",
+ "css-loader": "^3.2.0",
+ "style-loader": "^1.0.0",
"webpack": "^4.41.2",
"webpack-cli": "^3.3.10"
},
"dependencies": {
"react": "^16.11.0",
"react-dom": "^16.11.0"
}
}

There are two modes, which are development and production. The goal of development is strong source mapping and live reloading of localhost server (hot module replacement). The goal of production is minified bundles, lighter weight source maps, and optimized assets to improve load time.

In package.json add the code into ‘scripts’. It lets not to be concerned about their full paths (usage via the CLI):

"start": "webpack --mode development --watch",
"build": "webpack --mode production"
  • - watch means that after initial build, webpack will continue to watch for changes in any of the resolved files

HtmlWebpackPlugin will generate an HTML5 file that includes all the webpack bundles in the body using <script>. Install html-webpack-plugin by running the command:

npm install --save-dev html-webpack-plugin

Add the plugin to webpack.config.js:

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
entry: "./src/index.js",
output: { path: path.join(__dirname, "/dist"),
filename: "bundle.js"},
module: {rules:
[{test: /\.js$/,
exclude: /node_modules/,
use: ["babel-loader"]},
{test: /\.css$/,
use: ["style-loader", "css-loader"]}]},
plugins:
[new HtmlWebpackPlugin({
template: "./src/index.html"})]
};

Package.json

{"name": "react_project",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": { "test": "echo \"Error: no test specified\" && exit 1",
+ "start": "webpack --mode development --watch",
+ "build": "webpack --mode production"
},
"author": "",
"license": "ISC",
"devDependencies": { "@babel/core": "^7.6.4",
"@babel/preset-env": "^7.6.3",
"@babel/preset-react": "^7.6.3",
"babel-loader": "^8.0.6",
"webpack": "^4.41.1",
"webpack-cli": "^3.3.9",
+ "html-webpack-plugin": "^3.2.0",
"css-loader": "^3.2.0",
"style-loader": "^1.0.0",
},
"dependencies": {"react": "^16.10.2",
"react-dom": "^16.10.2"}
}

Run the command in terminal, which generate in dist file bundle.js which contains the transpiled ES5 code from index.js file:

npm start

It will also generate a file dist/index.html with the code:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>[project name]</title>
</head>
<body>
<div id="root">
</div>
<script type="text/javascript" src="bundle.js"></script></body>
</html>

Install the module webpack-dev-server. It will start a server instance and begin listening for connections from localhost on port: 8080:

npm install webpack-dev-server --save-dev

In package.json change “start”:

"start": "webpack-dev-server --mode development --open --hot"
  • — open tells dev-server to open the browser after server had been started. It set to true to open the default browser or
"start": "webpack-dev-server --mode development --open 'Google Chrome' --hot"
  • — open ‘Google Chrome’ opens Chrome on macOS or simply ‘Chrome’. ‘google-chrome’ on Linux and ‘chrome’ on Windows
  • — hot (Hot Module Replacement) exchanges, adds, removes modules while an application is running, without a full reload to speed up development.

Webpack-dev-server opens port: 8080 by default. To change the port:

"start": "webpack-dev-server --mode development --open --port 5000 --hot"
  • — port 5000 will open localhost on port 5000. It’s also possible to change the host

Package.json

{"name": "react_project",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": { "test": "echo \"Error: no test specified\" && exit 1"
"start": "webpack-dev-server --mode development --open --hot",
"build": "webpack --mode production"},
"author": "",
"license": "ISC",
"devDependencies": { "@babel/core": "^7.6.4",
"@babel/preset-env": "^7.6.3",
"@babel/preset-react": "^7.6.3",
"babel-loader": "^8.0.6",
"webpack": "^4.41.1",
"webpack-cli": "^3.3.9",
"css-loader": "^3.2.0",
"style-loader": "^1.0.0",
"webpack-dev-server": "^3.9.0"
},
"dependencies": {"react": "^16.10.2",
"react-dom": "^16.10.2"}
}

Run the command in terminal if it “start” in Package.json. It can also be “start:dev” if it be “start:dev”: “webpack-dev-server --mode development --open --hot”.

npm start
this is what to see

see it in GITHUB


Additional Information:

It’s good to use separate files for configurations, because development and production has different goals. It means to have separate webpack configurations for each environment. After separating the configurations, they have to be merged. To merge configurations install webpack-merge:

npm install — save-dev webpack-merge

Webpack.common.js will stay the same:

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
entry: "./src/index.js",
output: {
path: path.join(__dirname, "/dist"),
filename: "bundle.js"
},
module: {rules:
[{test: /\.js$/,
exclude: /node_modules/,
use: ["babel-loader"]},
{test: /\.css$/,
use: ["style-loader", "css-loader"]}]},
plugins:
[new HtmlWebpackPlugin({
template: "./src/index.html"})]};

Create webpack.dev.js:

const merge = require('webpack-merge');
const common = require('./webpack.config.js');

module.exports = merge(common, {
mode: 'development',
devtool: 'inline-source-map',
devServer: {contentBase: './dist',
},
});
  • devtool controls if and how the source maps are generated. inline-source-map is added as a DataUrl to the bundle.

Create webpack.prod.js:

const merge = require('webpack-merge');
const common = require('./webpack.config.js');
module.exports = merge(common, {
mode: 'production'
});

In package.json, change ‘scripts’:

"start": "webpack-dev-server --open --config webpack.dev.js",
"build": "webpack --config webpack.prod.js"
this is what to see

see it in GITHUB

Alyona Rodin

Written by

Degrees in Applied Mathematics, Software Engineer, and Statistics. Interested in AI, Mathematics, Development, Quantum Physics, Astronomy.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade