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.

Get Up And Run With Webpack And React

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.