Back to all posts

REACT JS Without Create React App - Build your own workflow

by Subin Sudhakaran / 24th July, 2020

Portfolio: subinsamrat.netlify.com

The easiest way to start practicing React is through Create React App (CRA). But we are choosing the hard path. In this posts, we will learn how to setup React workflow without create react app, so that we will be knowing what's happening under the hood.

At the end of this posts, you should be able to understand how Babel and Webpack fit into this ecosystem.

In the previous posts, we learned about the basic concepts that one need to know before jumping into React. Have a look at the previous post, so that it would be easier to grasp the React basics for newbies.

Check it out: REACT JS Concepts - This Tutorial Doesn’t Assume Any React Knowledge.

Steps involved in setting up React from scratch


1) Initializing npm and creating package.json file

2) Install React library

3) Example React code for analyzing the plugins needed

4) Installing webpack and babel packages

5) Creating webpack.config.js file for bundling components

6) Add babel transpiling ES6 features in webpack config file

7) Adding htmlWebpackPlugin to create index.html for direct deploy

8) Declaring babel-presets .babelrc file

9) Creating a simple Hello world application to test the setup

10) Issues faced on setup


Complete React BoilerPlate Github Code:

https://github.com/subinedge/ReactJS-Boiler-Plate

Let's get started.

Step 1: Initializing npm and creating package.json file


First, we will create a package.json file to manage the production and dev dependencies.

npm init -y

-y flag denotes a brand new package.json file has to be created with all the default values/configurations filled. This is how it looks like after initializing is done.

{
  "name": "React-boilerPlate",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

Step 2: Install React and ReactDOM


There are two packages from the NPM directory that we want to install. REACT and ReactDOM. Prior to v0.14, all ReactDOM functionality was part of React. As the name implies, ReactDOM is the glue between React and the DOM. Often, you will only use it for one single thing: mounting with ReactDOM.render(). For everything else, there's React. You use React to define and create your elements, for lifecycle hooks, etc. i.e. the guts of a React application.

npm install react react-dom

On successfully executing the above command, package.json will be getting updated with react and ReactDOM packages and also node_modules folder will be generated. Node modules contains the dependencies that react and reactDOM has. On further installing more and more packages from NPM, the node_modules folder will get bigger and bigger. Hence, it's advisable not to push the node_modules folder to Github as it will take too much time for uploading and also complete nightmare for the other person who will be downloading the code. Add the node_modules in .gitignore file.

Below entries will be added to package.json file.

"dependencies": {
  "react": "^16.13.1",
  "react-dom": "^16.13.1"
}

Step 3: Example React code for analyzing the plugins needed


We will create index.js file inside the src folder. We will make index.js file as the central integration file where all main component(App.js) will get declared and the mounting to DOM happens. So, by this time you have guessed the packages that will be present in the import statement. REACT and REACTDOM. We will create one component(App.js) and integrate it with index.js file.

Folder structure so far:

folder-structure-upto-react-reactDOM-installation


index.js:

import React from "react";
import ReactDOM from "react-dom";
import App from "./components/App";

ReactDOM.render(<App />, document.getElementById("root"));

components/App.js:

import React, { Component } from "react";

export default class App extends Component {
  render() {
    return (
      <div>
        <h1>Hello World!</h1>
      </div>
    );
  }
}

So in the above codes you might have noticed the ES6 syntax that is followed and JSX syntax that React follows. These has to be transpiled to browser compatible versions. This is where Babel comes into picture, which is the best tool for transpiling future JavaScript syntax to browser compatible JavaScript.

Babel packages needed:


  • babel-preset-env --> responsible for transpiling from ES6 to ES5

  • babel-preset-react --> responsible for converting React JSX syntax to JavaScript syntax

  • babel-loader & babel-core --> responsible for talking to Babel

Webpack packages needed:


Not only the transpiling alone is enough, bundling the javascript and css files needs to be done. For this, we are using Webpack.

  • webpack --> webpack package itself

  • webpack-dev-server --> local web server to view output of react app with hot reloading

  • webpack-cli --> responsible for running webpack commands in command line tool


Step 4: Installing webpack and babel packages


As above mentioned above, we will install the above mentioned NPM packages as dev dependencies.

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

"devDependencies": {
  "webpack": "^4.43.0",
  "webpack-cli": "^3.3.12",
  "webpack-dev-server": "^3.11.0"
}

npm install --save-dev babel-core babel-loader babel-preset-env babel-preset-react

"devDependencies": {
  "babel-core": "^6.26.3",
  "babel-loader": "^8.1.0",
  "babel-preset-env": "^1.7.0",
  "babel-preset-react": "^6.24.1"
}

Now we have installed most of the dependency NPM packages. Let's get started to setup the webpack config file.

Step 5: Creating webpack.config.js file for bundling components


Create webpack.config.js in root of the project folder. As we are bundling the mulitple javascript files into one and create the destination folder at runtime, we need path module.

webpack.config.js:

const path = require("path");

{/* specify the entry and bundled file and path */}
module.exports = {
  entry: "./src/index.js",
  output: {
    path: path.join(__dirname, "/dist"),
    filename: "index_bundle.js",
  },
};

We will be placing the dist folder in the same directory as webpack.config file present with filename as index_bundle.js.

Step 6: Add babel transpiling ES6 features in webpack config file


So far, we have wrote config for bundling js files. Next, we have to transpile the ES6 syntax to ES5.

module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader",
        },
      },
    ],
  }

We are having rules array where each rule has to be written as an object. First rule, we implemented is scanning for .js or .jsx extension files and using babel-loader plugin on it to transpile. We are excluding node_modules so that files inside of it won't get affected.

Step 7: Adding htmlWebpackPlugin to create index.html for direct deploy


Before getting into the installation part, we will see through the usage of htmlWebpackPlugin. Basically, this plugin will create index.html file for us with automatic addition of script tag in the body section of HTML file. We will just have to create a template and specify the path for the same, rest the plugin will take care.

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

webpack.config.js:

const HtmlWebpackPlugin = require('html-webpack-plugin');

{/* create plugins array under the module object */}

plugins: [
  new HtmlWebpackPlugin({
    template: './src/index.html'
  })
]

Create the template index.html under src folder.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>ReactBoilerPlate</title>
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>

Step 8: Declaring babel-presets .babelrc file


Inorder to use the presets (babel-preset-env & babel-preset-react) for transpiling ES6 to ES5 syntax and react JSX syntax preset, we have to declare the presets that we are using in .babelrc file in root of the project folder.

.babelrc:

{
  "presets": ["env", "react"]
}

Step 9: Creating a simple Hello world application to test the setup


Before running the react application, we have to setup the script commands for webpack dev server with hot reload.

"scripts": {
  "start": "webpack-dev-server --mode development --open --hot",
  "build": "webpack --mode production"
}

Above two script commands are for development and production. --open will open the localhost automatically once the command is entered in the terminal. --hot will auto reload the server on CTRL+S.

Build command is for production purpose where it will create the dist folder with bundled javascript file.

Step 10: Issues faced on setup


You might face an issue on babel-core module not found. Because the application expects babel core 7.x for babel loader 8.0. When we install babel core and babel loader without versioning, we get babel-core 6 and babel-loader 8.

babel-core-issue

So install,

npm install --save-dev @babel/core

Another issue on babel presets.

babel-presets-issue


For some reason the babel-preset-env & babel-preset-react doesn't work. So i googled and found that,

Just like env is now @babel/env, react should be @babel/react and you'll need to install @babel/preset-react & @babel/preset-env.

We have to change the value in .babelrc file as below:

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

and install both @babel/preset-react & @babel/preset-env to avoid the errors. And got successfully compiled.

react application output


Last but not least, we will check the build process and see if the dist folder is getting generated with bundled javascript file. Also the index.html file with script reference to index_bundle.js.

npm run build

react application build


react application build dist


The dist folder got generated and in the index.html, the script tag got added with correct bundled JavaScript file.

Post your doubts in subinsamrat96@gmail.com. I will be there for you guys, always. Thank you.