Get Up And Run With Webpack And React
In this article we will learn about Webpack, why we use it, its core concepts and how to setup react app with webpack.
Hello everyone, In this article we will learn about webpack. Here’s what I will discuss in this topic:
- Why we use Webpack
- What is Webpack
- Core Concepts of Webpack
- Setup react app with webpack
Now, let's start this amazing article
Why we use Webpack?
First of all, we need to look back to see how JavaScript is used before the webpack.
There are two ways.
- Include script for each functionality. Too many scripts can cause network bottleneck.
- A big .js file, leads to problem in scope, size, readability and maintainability.
To overcome these problems we use webpack.
What is Webpack?
Webpack is a module bundler for JavaScript applications. Webpack takes all the code from application and makes it reusable in a web browser. Modules are reusable chunks of code which are packaged to be used easily in website. Webpack becomes much easier to manage, debug, verify and test your code. Webpack build dependency graph which maps all the modules that your project needs. Here is the picture to understand webpack more clearly:
Core Concepts of Webpack
There are five core concepts of webpack are as follows:
- Entry
- Output
- Loaders
- Plugins
- Mode
Entry:
The point where the webpack will process to build out the dependency graph. Webpack figures out which other modules depend on the entry point, both directly and indirectly. It’ll look at the files that are imported into the entry point and continue to walk through imported files until it has accounted for all the code needed to run the application.
It is also possible to have multiple entry points. Here are some examples of entry point.
For single Entry Point:
module.exports ={
entry:{
app:'./src/index.js'
}
}
For Multiple Entry Point:
module.exports ={
entry:{
pageOne:'.src/pageOne/index.js',
pageTwo:'.src/pageTwo/index.js',
pageThree:'.src/pageThree/index.js'
}
}
For More Detail:
https://webpack.js.org/concepts/entry-points/
Output:
The point where the files are to be written on disk with name. The output can also use hash or chunk names to dynamically update the code when change and ensure to serve the correct code.
module.exports ={
entry:{
app:'.src/index.js'
},
output:{
filename:'[name].js',
pathname:__dirname + '/dist'
}
}
For More Detail:
https://webpack.js.org/concepts/output/
Loaders:
Webpack process other types of file by converting them into modules. The loaders are specified in the module key under rules. There are two configuration options required to add loader __ test identify file type and use tells which loader to use in order to transform files.
module.exports ={
output:{
filename:'bundle.js'
},
module:{
rules:[
{
test:/\.txt$/,
use:'raw-loader'
}
]
}
}
For More Detail:
https://webpack.js.org/concepts/loaders/
Plugins:
The tasks that can not be completed by a loader handle by Plugins. Plugins are used for bundle optimization , defining environment variables etc.Here is the example of generating index.html file for single page web application.
module.exports = {
output:{
filename:'bundle.js'
},
module:{
rule:[
{
test:/\.txt$/,
use:'raw-loader'
}
]
},
plugins:[
new HtmlWebpackPlugin({template:'./src/index.html'})
]
}
For More Detail:
https://webpack.js.org/concepts/plugins/
Mode:
Mode tells webpack which configuration and optimizations to use for your application. The mode are development and production. Development optimizes for faster build times and code readability for debugging. Production optimizes for smallest build possible,requiring a longer build time to shrink the code. If mode is not specified, Webpack automatically defaults to production.
module.exports = {
mode:'development'
};
/* Can be used in CLI webpack--mode = production */
Setup React with Webpack:
Reactjs is the most popular javascript library which is used by millions of developers around the globe. Creating a React app from Scratch is painful as it requires a lot of configuration. We all know that create-react-app gives a nice boilerplate to begin a journey with react, but it lacks some amount of configuration.
Pre-requisites:
Install Nodejs & npm on your machine
After installing nodejs and npm, start building react app with webpack. So, I have decided to divide this into different steps
Let's start the code
First, create a project folder and cd into it
mkdir react_webpack && cd react_webpack
Create a package.json file into the root of our project folder ‘react_webpack’:
npm init
If you want to skip all the questions asked during the creation of package.json with above command, run:
npm init -y
Create an “src folder, index.js,and index.html” file:
mkdir -p src
touch src/index.html src/index.js
Here, index.html and index.js files will serve as the entry point in our react application.
Let’s install React.js and React DOM:
npm install react react-dom
Now, we will install Babel & Webpack
babel-core: babel transpile ES6 code to ES5.
babel-loader: This is a webpack helper which allows to transpile Javascript files with babel and webpack. It uses babel under the hood.
babel/preset-env: It determines which features needs to be transformed to run within different browsers or runtime versions. This is also known as browser polyfills
babel/preset-react: It is used to transform all your React JSX into functions.
npm install @babel/core babel-loader @babel/preset-env @babel/preset-react @babel/plugin-proposal-class-properties --save-dev
You must have to install webpack and webpack-cli as a dev dependency
npm install webpack webpack-cli --save-dev
Now, create a webpack.config.js file inside our project folder and insert the below code into it
touch webpack.config.js
const path = require('path');
module.exports = {
//Entry Point
entry:{
app:'./src/index.js'
},
//Output
output:{
path: path.resolve(__dirname + '/dist'),
filename:'app.bundle.js',
publicPath: '/'
}
//Loader
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
}
]
}
};
Now, Install webpack-dev-server
Webpack-dev-server: Webpack has its own server called webpack-dev-server(WDS) which removes the pain of manually refreshing the browser once the changes have been saved.
npm install webpack-dev-server --save-dev
Insert below code in the webpack.config.js file
const path = require("path");
module.exports = {
//Entry Point
entry: {
app: "./src/index.js"
},
//Output
output: {
path: path.resolve(__dirname + "/dist"),
filename: "app.bundle.js",
publicPath: '/'
},
//webpack dev server
devServer: {
compress: true,
port: 3000,
stats: "errors-only",
open: true
},
//Loader
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
}
]
}
};
In this we have to change some code later but at that time continue with it
— open: This will open the default browser and load the localhost environment running your app in the browser
Now add below lines inside the package.json file
"scripts": {
"start": "webpack-dev-server",
"build": "webpack --mode production"
},
Insert below code into your index.js
import React from "react";
import ReactDOM from "react-dom";
const App = () => {
return <div>Hello React,Webpack 4 & Babel 7!</div>;
};
ReactDOM.render(<App />, document.querySelector("#root"));
Insert the below code into your index.html files
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<div id="root"></div>
</body>
</html>
Install another webpack helper, css-loader and style-loader to make CSS work in our application. We will be importing CSS files into our components.
npm install css-loader style-loader file-loader --save-dev
Install another webpack helper, sass-loader to load the .scss file and node-sass that will do actual compilation and mini-css-extract-plugin to extract the css file into another bundle
npm install sass-loader node-sass mini-css-extract-plugin --save-dev
Now you webpack.config.js file will look like:
const path = require("path");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
//Entry Point
entry: {
app: "./src/index.js"
},
//Output
output: {
path: path.resolve(__dirname + "/dist"),
filename: "app.bundle.js",
publicPath: '/'
},
//webpack dev server
devServer: {
compress: true,
port: 3000,
stats: "errors-only",
open: true
},
//Loader
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
{
test: /\.css$/i,
use: ["style-loader", "css-loader"]
},
{
test: /\.scss$/,
use: [
{
loader: MiniCssExtractPlugin.loader
}
][("css-loader", "sass-loader")]
},
{
// For images
test: /\.(png|jpe?g|gif|svg)$/,
use: [
{
//Using File-loader for these files
loader: "file-loader",
/*In options we can set different things like format
and directory to save*/
options: {
outputPath: "images"
}
}
]
},
{
//For fonts
test: /\.(woff|woff2|ttf|otf|eot)$/,
use: [
{
//using file-loader too
loader: "file-loader",
options: {
outputPath: "fonts"
}
}
]
}
]
},
//plugin
plugins: [
new MiniCssExtractPlugin({
filename: "app.css",
disable: false,
allChunks: true
})
]
};
Create a .babelrc file inside the root of your project folder and insert below lines to it.
.babelrc: As we know that, we are using babel-loader, it will look for a .babelrc file while the project is initialized
touch .babelrc
Insert below code into your .babelrc files
{
"presets": [
[
"@babel/preset-env",
{
"useBuiltIns": "usage",
"corejs": {
"version": 3,
"proposals": true
}
}
],
"@babel/preset-react"
],
"plugins": [
"@babel/plugin-proposal-class-properties"
]
}
Install HTML webpack plugin and HTML loader for displaying our page
htmlWebPackPlugin: This generates the HTML dynamically, with an <script> tag including our bundled js file.
And also install CleanWebpackPlugin and Dotenv plugin. CleanWebpackPlugin clean your build folder(s).Dotenv wraps dotenv and Webpack.DefinePlugin. As such, it does a text replace in the resulting bundle for any instances of process.env.
npm install html-webpack-plugin html-loader clean-webpack-plugin --save-dev ```
npm install dotenv-webpack --save
Here is how our webpack.config.js file will look like:
const path = require("path");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const HtmlWebPackPlugin = require("html-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const Dotenv = require("dotenv-webpack");
module.exports = {
//Entry Point
entry: {
app: "./src/index.js"
},
//Output
output: {
path: path.resolve(__dirname + "/dist"),
filename: "app.bundle.js",
publicPath: '/'
},
//webpack dev server
devServer: {
compress: true,
port: 3000,
stats: "errors-only",
open: true
},
//Loader
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: "babel-loader"
},
{
test: /\.css$/i,
use: ["style-loader", "css-loader"]
},
{
test: /\.scss$/,
use: [
{
loader: MiniCssExtractPlugin.loader
}
][("css-loader", "sass-loader")]
},
{
// For images
test: /\.(png|jpe?g|gif|svg)$/,
use: [
{
//Using File-loader for these files
loader: "file-loader",
/*In options we can set different things like format
and directory to save*/
options: {
outputPath: "images"
}
}
]
},
{
//For fonts
test: /\.(woff|woff2|ttf|otf|eot)$/,
use: [
{
//using file-loader too
loader: "file-loader",
options: {
outputPath: "fonts"
}
}
]
},
{
test: /\.html$/,
use: "html-loader"
}
]
},
//plugin
plugins: [
new Dotenv(),
new HtmlWebPackPlugin({
template: "./src/index.html",
filename: "./index.html"
}),
new MiniCssExtractPlugin({
filename: "app.css",
disable: false,
allChunks: true
}),
new CleanWebpackPlugin({
cleanOnceBeforeBuildPatterns: ["dist"]
}),
]
};
Here is the Link of Loaders that is used in this article for more details:
Style-loader: https://github.com/webpack-contrib/style-loader
Babel-loader: https://github.com/babel/babel-loader
Css-loader: https://github.com/webpack-contrib/css-loader
File-loader: https://github.com/webpack-contrib/file-loader
Sass-loader: https://github.com/webpack-contrib/sass-loader
Html-loader: https://webpack.js.org/loaders/html-loader/
Here is the Link of plugins for more detail that we used in this article:
HtmlWebpackPlugin:
https://webpack.js.org/plugins/html-webpack-plugin/
MiniCssExtractPlugin:
https://github.com/webpack-contrib/mini-css-extract-plugin
CleanWebpackPlugin:
https://github.com/johnagan/clean-webpack-plugin
Dotenv(Environment Variable):
https://www.npmjs.com/package/dotenv-webpack
Here is how our package.json looks like :
{
"name": "react_webpack",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"dev": "webpack-dev-server."
"build": "webpack --mode production"
},
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.7.2",
"@babel/preset-env": "^7.7.1",
"@babel/preset-react": "^7.7.0",
"babel-loader": "^8.0.6",
"clean-webpack-plugin": "^3.0.0",
"css-loader": "^3.2.0",
"file-loader": "^4.3.0",
"html-loader": "^0.5.5",
"html-webpack-plugin": "^3.2.0",
"mini-css-extract-plugin": "^0.8.0",
"sass-loader": "^8.0.0",
"style-loader": "^1.0.0",
"webpack": "^4.41.2",
"webpack-cli": "^3.3.10",
"webpack-dev-server": "^3.9.0"
},
"dependencies": {
"dotenv-webpack": "^1.7.0",
"react": "^16.12.0",
"react-dom": "^16.12.0"
}
}
Now Run,
npm run dev
To make the build, run
npm run build
Great, now we have successfully created the react app with webpack. Feel free to fork the code and run all commands which I have mentioned above.