Setting up a React app from scratch withWebpack, Babel and Eslint

shalitha senanayaka
Geek Culture
Published in
9 min readMay 2, 2021

New to JavaScript? Take 5 minutes from your valuable time and read this!! I assure you it will not go to waste,

We all know the magic command create-react-app .However, if you are doing anything requiring SASS, Webpack configurations, or other custom configurations, CRA (create-react-app) will be a pain. Like, if you want to add custom build configs. One way to add custom configs is to eject the app.

If you are a naturally curious developer, you’d like to know how things work and which part does what, then let me help you with it.

Prerequisites

  1. Node
  2. Any IDE (recommended Webstorm or Visual Studio Code).

Let’s Start

Open up the command line or Git bash and create a new directory:

mkdir custom-react-boilerplate && cd custom-react-boilerplate

Initialize project by running:

npm init

It will prompt you for input for a few aspects of the project. fill that inputs as your own. Then you can see the package.json file.

Then we install react

npm install react react-dom

Setup Webpack

Webpack is a bundler. The core function of Webpack is that it takes a bunch of JavaScript files we write in our project and turns them into a single, minified file so that it will be quick to serve.

Let’s install the Webpack.

npm install --save-dev webpack webpack-dev-server webpack-cli html-loader html-webpack-plugin
  • webpack — includes all core Webpack functionality.
  • webpack-dev-server — this development server automatically re-runs Webpack when our file is changed.
  • webpack-cli — enable running Webpack from the command line.

Next, we configure the package.json to run the Webpack.

"scripts": {
"start": "webpack serve --mode development --env=development",
},
  • — mode means that configure the option to tells the webpack to run stage. For further information visit https://webpack.js.org/configuration/mode/
  • — env means that we set the running environment. This parameter we use in below topic source map for better error logs.

The following string values are supported:

webpack run stages

Then we create a index.html file at the root of the project as,

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Custom React Configuration</title>
</head>
<body>
<div id="root"></div>
</body>
</html>

So two highlighted things, you have to create an <div id="root"></div> element and an <script src="./dist/bundle.js"></script> tag.

Add src directory then index.jsx and App.jsx file

mkdir src && cd src && touch index.jsx && touch App.jsx

Now let’s add some starter code,

In the App.jsx file,

import React from "react";

function App()
{
return (
<div className='App'>
<h1>Hello World !</h1>
</div>
);
}

export default App;

In the index.jsx file,

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

ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root'),
);

First, we create App.jsx and import it to the index.jsx. This approach isolates the complexity and understandable than the put all stuff together. So a couple of things have to clarify,

What is React.StrictMode ?

React’s StrictMode is sort of a helper component that will help you write better react components, you can wrap a set of components with the <StrictMode> .

StrictMode currently helps with:

for further information refer: https://reactjs.org/docs/strict-mode.html

Configuring Babel 7

Ok, what is Babel, and why we need it?

Babel is responsible to converting new language features to old.

While most popular browsers can support ECMAScript2015 ( or ES6), it’s always good practice to ensure that your code is compatible with older versions of JavaScript. Es6 have let, const, arrow functions, classesetc. To understand, below we have an input of an ES6 arrow function which is converted to a plain, old ES5 JavaScript function.

// Babel Input: ES2015 arrow function
[1, 2, 3].map((n) => n + 1);

// Babel Output: ES5 equivalent
[1, 2, 3].map(function(n) {
return n + 1;
});

Further reference: https://babeljs.io/docs/en/

Let’s install Babel into our project,

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

What we just installed:

  • @babel/core: Main dependency that includes the babel transform script.
  • @babel/preset-env: Transform ES6+ into valid ES5 code. Optionally configures browser polyfills automatically.
  • @babel/preset-react: extends Babel support to JSX.
  • babel-loader: Webpack loader that hooks Babel into webpack. We will run Babel from webpack with this package.

To configure Babel into our webpack, create a file in your root directory with the name webpack.config.js file:

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

module.exports = {
entry: './src/index.jsx',
output: {
path: path.resolve(__dirname, 'build'),
publicPath: '/',
filename: 'bundle.js'
},
resolve: {
alias: {
components: path.resolve(__dirname, 'src'),
},
extensions: ['.js', '.jsx'],
},
devServer: {
contentBase: "./build",
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: ['babel-loader']
},
{
test: /\.less$/,
use: [
'style-loader',
'css-loader',
'less-loader',
],
},
]
},
plugins: [
new HtmlWebpackPlugin({
template: path.resolve('./index.html'),
}),
]
};

Now we clarify what are the configurations that set in webpack.config.js file.

entry is our main JavaScript file. In React, this is the file where we use our renderer.

output tells where to put our bundled code and what to name the file. Here, we configure Webpack to create a directory named /dist in the root directory and create a file named bundle.js.

output tell the server to serve content from contentBase config.

"module" is where we tell Webpack to use all of those loaders we installed before.

Next, Babel presets, create a new .babelrc file in the root of the project.

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

Now run npm run start . You can see the Hello world !.

source map for better error logs

A source map provides the browser with a means of mapping back code within a compressed file back to its original position in a source file. This way, when an error occurs, you’re pointed to the exact file and line from which it emanates from. So if you’re using any tool that minifies, concatenates, or bundles up your code, you’ll definitely need to generate source maps.

So we modify the devtool in the webpack.config.js

devtool : isProduction ?'source-map' : 'inline-source-map'

Now the webpack.config.js looks like,

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

module.exports = (env) => {
const isProduction = env === 'production';
return{
entry: './src/index.jsx',
output: {
path: path.resolve(__dirname, 'build'),
publicPath: '/',
filename: 'bundle.js'
},
resolve: {
alias: {
components: path.resolve(__dirname, 'src'),
},
extensions: ['.js', '.jsx'],
},
devServer: {
contentBase: "./build",
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: ['babel-loader']
},
{
test: /\.less$/,
use: [
'style-loader',
'css-loader',
'less-loader',
],
},
]
},
plugins: [
new HtmlWebpackPlugin({
template: path.resolve('./index.html'),
}),
],
devtool : isProduction ?'source-map' : 'inline-source-map'
}

};

Setting up ESLint

A great project is made out of consistent code. The code should be indistinguishable from its writer: You should not be able to tell who authored which line of code in the project. Eslint helps developers to write better code by pointing out common errors and enforcing good programming patterns.

Linters highlights syntactical and stylistic problems in your source code, which often times helps you identify and correct subtle programming errors or unconventional coding practices that can lead to errors.

Let’s install ESLint into our project:

npm --save-dev install eslint eslint-loader babel-eslint eslint-config-react eslint-plugin-react

after that run eslint --init in the terminal. Then please follow order,

We select Eslint to check syntax, problems and also enforce code style for code consistancy.

I personally prefer import/export statements. Choose your interested one.

Our application is a React-based application. So we need to select React.

We not going to use typescript here. So we select No.

Our React application is running on the browser. So we select Browser only.

I recommend using popular style guidelines.

I personally like Airbnb’s style guidelines. So I choose Airbnb and if you prefer something different. please take your own selection.

Here Eslint asks to create a configuration file as a JS, YAMLor JSON. I personally prefer JSON-type configuration files. SO I choose JSON.

Sometimes Eslint asks to install some plugins. So please select YES.

Now you can see theeslintc.jsonfile is created in the project root folder. This is the configuration file of the Eslint.

We have to modify the webpack.config.jsalso.

use: ['babel-loader', 'eslint-loader'] // include eslint-loader

Now the file webpack.config.js looks like,

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

module.exports = (env) => {
const isProduction = env === 'production';
return{
entry: './src/index.jsx',
output: {
path: path.resolve(__dirname, 'build'),
publicPath: '/',
filename: 'bundle.js'
},
resolve: {
alias: {
components: path.resolve(__dirname, 'src'),
},
extensions: ['.js', '.jsx'],
},
devServer: {
contentBase: "./build",
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: ['babel-loader', 'eslint-loader']
},
{
test: /\.less$/,
use: [
'style-loader',
'css-loader',
'less-loader',
],
},
]
},
plugins: [
new HtmlWebpackPlugin({
template: path.resolve('./index.html'),
}),
],
devtool : isProduction ?'source-map' : 'inline-source-map'
}

};

for further reference: https://eslint.org/

To extend the eslint rules. I put some custom rules for better coding conventions. If your want to extend eslint rules, Goto theeslintc.jsonfile and put your custom rules inside the "rules":{}.

If you interested in custom rules please refer: https://github.com/ShalithaCell/Eslint-Rules-ReactJs

So we again run the project npm run start

Oh.. a lot of errors are showing up in the console,

These errors are coming from the Eslint.

Errors! What do I do?

There are multiple ways to resolve Eslint errors and warnings.

  • use — fix command
  • setup IDE to check Eslint configurations.

1. Use — fix

Add the following line to package.json the file.

"scripts": {
"lint": "eslint --fix --ext .js,.jsx ."
}

now script tag like,

"scripts": {
"start": "webpack serve --mode development",
"lint": "eslint --fix --ext .js,.jsx .",
"test": "echo \"Error: no test specified\" && exit 1"
},

Then run it with npm run lint

So we again run the project npm run startand check errors are gone.

2. Setup IDE to check Eslint configurations.

Refer to the below link for configuring WebStrom and VS Code.

Setup LESS with React

Less is a backward-compatible language extension for CSS.

For further reference: https://lesscss.org/

Let's install the necessary packages,

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

Please check your webpack configuration module property like below (we configure LESS properties earlier):

module : {
rules : [
{
test : /\.(js|jsx)$/,
exclude : /node_modules/,
use : [ 'babel-loader', 'eslint-loader' ],
},
{
test : /\.less$/,
use : [
'style-loader',
'css-loader',
'less-loader',
],
},
],
},

Finally your package package.jsonfile scripts look,

"scripts": {
"start": "webpack serve --mode development --env=development",
"lint": "eslint --fix --ext .js,.jsx .",
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack --mode production --env=production"
},

Conclusion

We just created our own React project boilerplate. fully functioning React app built without using create-react-app. I hope this helps clarify at least some of what’s happening under the hood of the React apps you’ve already built.

Source code: https://github.com/ShalithaCell/React-Custom-BoilerPlate

--

--

shalitha senanayaka
Geek Culture

I’m Shalitha, Software Engineer who loves to code 24/7. For more information, feel free to reach me at www.shalitha.info