Setting up React Toolchain Manually - A Guide to Understanding NPM, Webpack, and Babel
In this tutorial, we will set up the React toolchain from scratch. Create-react-app does all of this for us. All these configurations can be shown when we eject react configuration. But it is worth to set up things manually to understand what is going under the hoods.
NPM
NPM stands for Node Package Manager. NPM manages all the third-party libraries that we will be using. NPM will be installed by default with NodeJS.
NPM & Webpack Initialization
First, let's navigate by terminal to our empty project directory. Now, run npm init -y
This will create a new file called package.json
with all default
To add Webpack to our project run npm install --save-dev webpack webpack-cli
. The package.json file is updated as it includes a new section called devDependencies.
Create a new file called index.js
under src
directory. As following
All we need to do now is run Webpack: npx webpack
A new folder (dist) is generated with one file main.js
Babel
Babel is a JavaScript compiler. It lets you write a modern JavaScript code that still works in older browsers.
First, we need to install some dev dependencies npm install -save-dev @babel/core @babel/cli @babel/preset-env
both @babel/core
and @babel/cli
are required to compile files where @babel/preset-env
is a smart preset used handle syntax transformation without doing micromanage for the environment.
To see code tranfromation run npx babel ./src/index.js --presets=@babel/preset-env
.
Adding Babel to Webpack
At the begining, we need to add new dev dependency npm install -D babel-loader
and update webpack.config.js file to include the following changes
module: {
rules: [
{
test: /\.js$/,
loader: "babel-loader",
exclude: /node_modules/,
options: {
presets: ["@babel/preset-env"],
},
},
]
}
Now when we run Webpack, it will bundle our transformed code.
Adding React preset
Now, let's transform our project to ReactJS by installing the following dependencies npm install -save react react-dom
and add two new files:
App.js
import React from "react";
class App extends React.Component {
render() {
return <div>This is App Component</div>;
}
}
export default App;
index.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
ReactDOM.render(<App />, document.getElementById("root"));
Once we run Webpack we will get a syntax error saying that it is unable to tranform
To solve this issue, we need to add a new preset for React npm i -D @babel/preset-react
and update webpack.config.js file
module: {
rules: [
{
test: /\.js$/,
loader: "babel-loader",
exclude: /node_modules/,
options: {
presets: ["@babel/preset-env", "@babel/preset-react"],
},
},
]
}
Adding HTML Loader
To auto-generate HTML file with the latest bundle we need to add new Depenecey npm i -D html-webpack-plugin
and modify webpack.config.js file by adding new plugin as follow:
const HtmlWebpackPlugin = require('html-webpack-plugin')
plugins: [
new HtmlWebpackPlugin({
template: "./public/index.html",
}),
],
Adding webpack-dev-server
Webpack-dev-server will provide live reloading to our application. First install webpack-dev-server by npm i -D webpack-dev-server
. And run npx webpack-dev-server
.
to customize Running port add devServer to Webpack configuration
devServer: {
port: 3000,
},
Adding CSS loader
To load CSS files into JavaScript using Webpack and Babel we need a special presets for that npm i -D css-loader style-loader
Update Webpack configuration file by adding new rule under the modules section
{
test: /\.css$/,
use: ["style-loader", "css-loader"],
exclude: /node_modules/,
},
Adding Babel Plugins
Now, change App.js file to the following:
import React from 'react'
class App extends React.Component {
state = {
count: 0
}
render() {
return (
<div>
<h1>Hello World!</h1>
<h2>Count: {this.state.count}</h2>
<button onClick={() => this.setState(state => ({count: state.count + 1}))}>+</button>
<button onClick={() => this.setState(state => ({count: state.count - 1}))}>-</button>
</div>
)
}
}
export default App
Bable will now give us a new syntax error because defining a state outside constructor is not supported by javascript doesn't support such syntax. We need to add a new plugin to Babel ( Before we added html-webpack-plugin as Webpack plugin). Install npm i -D @babel/plugin-proposal-class-properties
, and now we need to update Webpack configuration as following:
const path = require("path");
const webpack = require("webpack");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
entry: "./src/index.js",
devServer: {
port: 3000,
},
devtool: "source-map",
output: {
path: path.join(__dirname, "build"),
filename: "bundle.js",
},
module: {
rules: [
{
test: /\.js$/,
loader: "babel-loader",
exclude: /node_modules/,
options: {
presets: ["@babel/preset-env", "@babel/preset-react"],
plugins: ["@babel/plugin-proposal-class-properties"],
},
},
{
test: /\.css$/,
use: ["style-loader", "css-loader"],
exclude: /node_modules/,
},
],
},
plugins: [
new HtmlWebpackPlugin({
template: "./public/index.html",
}),
],
};