Easy Custom Webpack Setup for React.js Applications
Tags: webpack, javascript, react
Published: 2019-07-24 15:46:09

---
title: Easy Custom Webpack Setup for React.js Applications
published: true
description: Webpack is currently the most popular code bundler but can be quite confusing. In this guide, we present a custom configuration for React.js apps.
tags: webpack, JavaScript, React
canonical_url: https://blog.jscrambler.com/easy-custom-webpack-setup-for-react-js-applications/
cover_image: https://blog.jscrambler.com/content/images/2019/07/jscrambler-blog-easy-custom-webpack-setup-react-applications-1.jpg
---

It should be self-evident that web applications keep growing in terms of their capabilities.

Web apps are close to or more powerful than their desktop counterparts. With this power, comes a lot of complexity. For a simple application, some of these complexities include: CSS and JavaScript minification, JavaScript and CSS code concatenation, image loading in JavaScript files, file watching, and auto-compilation. We will get into these in more detail later.

In light of this, several tools have been created to make development and shipping easier and more efficient. One such tool is [webpack](https://webpack.js.org/). There are many contenders in this field, [Gulp](https://gulpjs.com/) and [Browserify](http://browserify.org/) being two. In this tutorial, we will be demonstrating how to setup webpack for a [React.js application](https://reactjs.org). The reason we are using webpack is that many major web frameworks use it, including the official React.js compiler, [create-react-app](https://reactjs.org/docs/create-a-new-react-app.html#create-react-app). Webpack is in fact the most popular build tool according to the 2018 State of JavaScript survey, as pictured below:

![Webpack Popularity](https://blog.jscrambler.com/content/images/2019/07/jscrambler-blog-easy-custom-webpack-setup-react-applications-webpack-popularity.png)

Please find the finished project code in this [GitHub repo](https://github.com/JscramblerBlog/Jscrambler-Webpack-React).

## Compilation Requirements of a Simple Web Application

* Minification: This is the process of reducing code filesize. It is done by removing unnecessary whitespace. Other techniques include renaming functions and variable names.
* Concatenation: This is the method of combining several files into one.
* Image loading in JavaScript and CSS files: This is a method used to generate URLs for image files based on their configured location.
* File watching and auto-compilation: This is a method wherein a specified process will self-run when the contents of a file have changed.
* Auto-reloading: This goes hand in hand with file watching and auto-compilation. The only extra step it adds is that, after compilation, the page is auto-reloaded.

## Summary of webpack Concepts
Webpack works with the concept of entry point and output. The entry and output setting are configured in a file called `webpack.config.js`. Additional configurations are possible in this file and we will look at some of the common ones.

### Entry Point

The entry point is a JavaScript file. It is the main file which will import all other required files. Using [JavaScript import syntax](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import), webpack knows how to read this entry file. It will also link up all the other files in there.

### Output
This is a single JavaScript file. It will be the total of all the files which webpack has managed to process after reading the entry file. This is usually the script which we will end loading on our webpage using `<script src="somepath/output.js"></script>`, for example. This process where we end up with a single file is called bundling. The resulting single file is usually called a bundle.

### Modules
These are sets of rules which control how webpack will behave. An example would be: which file extensions to consider when concatenating JavaScript code.

### Plugins
Plugins add extra capability to webpack to what already exists by default.

## Setting up webpack for a Simple Web Application
We will begin with a simple React.js application.

Initialize an npm project using:

```bash
npm init -y
```

Install several npm packages below

```bash
npm install --save react react-dom prop-types // react stuff
npm install --save-dev webpack webpack-cli // webpack and it's cli
npm install --save-dev css-loader mini-css-extract-plugin // css compilation
npm install --save-dev babel-loader @babel/core @babel/preset-env @babel/preset-react // es6 and jsx stuff
npm install --save-dev html-webpack-plugin //  inserts output script to index.html file
npm install --save-dev clean-webpack-plugin // to cleanup(or empty) the dist(or output) folder before compilation
npm install --save-dev sass-loader node-sass // sass to css compilation
npm install --save-dev file-loader // loading files, e.g. images, fonts
npm install --save-dev papaparse csv-loader xml-loader // xml, csv and tsvs loading
npm install --save-dev webpack-dev-server // webpack development server
```

In an empty folder, create a webpack config file with the name `webpack.config.js` and insert the following content;

```javascript
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = {
 mode: "development",
 entry: {
   app: "./src/main.js"
 },
 devtool: 'inline-source-map',
 devServer: {
   contentBase: path.join(__dirname, './'), // where dev server will look for static files, not compiled
   publicPath: '/', //relative path to output path where  devserver will look for compiled files
 },
 output: {
   filename: 'js/[name].bundle.js',
   path: path.resolve(__dirname, 'dist'), // base path where to send compiled assets
   publicPath: '/' // base path where referenced files will be look for
 },
 resolve: {
   extensions: ['*', '.js', '.jsx'],
   alias: {
     '@': path.resolve(__dirname, 'src') // shortcut to reference src folder from anywhere
   }
 },
 module: {
   rules: [
     { // config for es6 jsx
       test: /\.(js|jsx)$/,
       exclude: /node_modules/,
       use: {
         loader: "babel-loader"
       }
     },
     { // config for sass compilation
       test: /\.scss$/,
       use: [
         {
           loader: MiniCssExtractPlugin.loader
         },
         'css-loader',
         {
           loader: "sass-loader"
         }
       ]
     },
     { // config for images
       test: /\.(png|svg|jpg|jpeg|gif)$/,
       use: [
         {
           loader: 'file-loader',
           options: {
             outputPath: 'images',
           }
         }
       ],
     },
     { // config for fonts
       test: /\.(woff|woff2|eot|ttf|otf)$/,
       use: [
         {
           loader: 'file-loader',
           options: {
             outputPath: 'fonts',
           }
         }
       ],
     }
   ]
 },
 plugins: [
   new HtmlWebpackPlugin({ // plugin for inserting scripts into html
   }),
   new MiniCssExtractPlugin({ // plugin for controlling how compiled css will be outputted and named
     filename: "css/[name].css",
     chunkFilename: "css/[id].css"
   })
 ]
};
```

### Input JS File
Create an input JavaScript file in `src/main.js` and paste in the following;

```javascript
import React from "react";
import ReactDOM from "react-dom";
import Main from "@/components/Main";
import  "./style.scss";

ReactDOM.render(<Main/>, document.getElementById('app'));

if (module.hot) { // enables hot module replacement if plugin is installed
 module.hot.accept();
}
```

Create a React component file in `src/components/Main.jsx` with the contents;

```jsx
import React, { Component } from "react";

export class Main extends Component {
 render() {
   return (
     <div>
       <p className="hello-text">Hello from react!</p>
     </div>
   )
 }
}

export default Main
```

### Compiling React JSX to JavaScript (Presets)

Create a file at `.babelrc` and put the following content;

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

This sets which features of ES6 to load for React.js. Do not forget the period `.` in the filename. It allows us to use the special syntax of React in native JavaScript code. Things like:

```
import Main from "@/components/Main";

<Main/>
```

### Output a Single CSS File
Create a Sass file in `src/style.scss` with the following contents;

```css
.hello-text {
 color: red;
}
```

### Output a Single JavaScript File
In `package.json`, add the following to the scripts section;

```json
"dev": "webpack-dev-server"
"production": "webpack --mode production"
```

When we run the command, `npm run dev`, the development server will be started. We can see the results of the running project at `http://localhost:8080/`. Running `npm run production` compiles the file in production mode and puts the result in the `dist` directory.

### Output Images

In the file `src/components/Main.jsx`, import an image of your choice using the line:

```javascript
import imagename from "@/images/imagename.jpg";
```

Make sure you store the image in the folder `src/images/imagename.jpg`.

Use the image in the components render function using:

```html
<p><img src={imagename} alt="Image name"/></p>
```

Now, the image should be visible in the browser.

### Output Fonts

For fonts, inside the file `src/style.scss`, load the fonts using a syntax similar to the following;

```javascript
@font-face {
 font-family: "Advent Pro";
 font-style: normal;
 font-weight: 400;
 src: url("./fonts/advent-pro-v9-latin-regular.woff2") format("woff2"),
   url("./fonts/advent-pro-v9-latin-regular.woff") format("woff");
}
```

In the case above, we are loading a font using two font files and giving it the name `Advent Pro`

Use the new font in the `hello-text` class:

```css
font-family: "Advent Pro";
```

### Set Up File Watching

Due to the fact that we are using `webpack-dev-server`, we automatically get file watching and auto-reloading.

## Setting up webpack for More Advanced Web Applications

In addition to the above simple setup, let's add more features for a slightly more complex application.

### Setting up Hot Module Replacement
This is similar to auto reloading except that it does not reload the page. Instead, it smartly injects only the parts of the files which have changed.

To add the functionality, add the following to the `devServer` config in the webpack config file `webpack.config.js`:

```javascript
hot: true
```

### Splitting Output JavaScript Files into Separate Files

Sometimes, we may want many output files for some reason. An example would be to reduce cache-busting impact because of files that change often. Create another file entry file in `src/print.js` and add in the following:

```javascript
console.log("This comes from print file");
```

This is just a simple log message in the console. In a real application though, we would probably have a lot more code in here.

Then, change the entry config like below;

```javascript
entry: {
 app: "./src/main.js",
 print: "./src/print.js"
},
```

Now, we have two script files for the output.

### Create Production Files

By now, you will notice that, when we run `npm run dev`, there are no compiled files in the output folder `dist`. That is because we are using the development server. If we want files for distribution, we need to use webpack's built-in compiler. We can do that by adding this to the script section of `package.json`:

```json
"build": "webpack",
```

Now, when we run `npm run build`, a `dist` folder will be created with the distribution files. To prepare that for production, add the flag as below:

```json
"production": "webpack --mode production",
```

### Clear Output Folders Before Regeneration

Sometimes, we may want to clear the `dist` folder before creating the production files. One example is when you have file names randomly generated. In that case, there will be duplicates in some folders.

To do that, add the following to the list of plugins in the config file;

```javascript
new CleanWebpackPlugin({
 cleanOnceBeforeBuildPatterns: ["css/*.*", "js/*.*", "fonts/*.*", "images/*.*"]
}),
```

This is clearing all the folders named `js`, `fonts` and `images`. To test out that it works, add a random JavaScript file to `dist/js`. For example `randomfile.js`.

Run `npm run build` with the plugin configuration above commented out. You will notice that the file still remains.

Now uncomment the plugin configuration and rerun `npm run build`. The file will now disappear.

### Custom HTML Template

Create a file in `src/index.html` with the following contents:

```html
<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <meta http-equiv="X-UA-Compatible" content="ie=edge">
   <title>Learn Webpack</title>
</head>
<body>
   <div id="app"></div>
</body>
</html>
```

Now run `npm run build`. Look at the output of the file in `dist/index.html`. You will notice that it is not using the source HTML file in `src/index.html` as a template because the titles are different. To configure that, change the `HtmlWebpackPlugin` plugin in the webpack config file by passing in an object like below:

```javascript
new HtmlWebpackPlugin({
 template: "./src/index.html",
 filename: "index.html",
 title: "Learning Webpack"
}),
```

Now rerun `npm run build`. You will notice that the titles are now the same.

### Serving Other Static Asset Types

You will have noticed that when we build our project, the images and fonts are copied over to the `dist` folder. We can not only copy over images and fonts but we can access in our code other file types like csv.

To add support for csv, create a file called `src/mycsv.csv` and paste in some csv as so;

```csv
name,company,email,date
Raja,Sem Corporation,pede.ultrices.a@tinciduntpedeac.co.uk,"January 21st, 2019"
Aladdin,Ut Nulla Corp.,hendrerit.consectetuer@interdumSed.ca,"November 21st, 2018"
Plato,Fermentum Fermentum Limited,semper.egestas@massaMauris.net,"October 7th, 2019"
Anthony,Fringilla Est Consulting,luctus.ut@tortornibhsit.co.uk,"April 18th, 2018"
```

Then, add the following settings to the list of loader rules in the webpack config file:

```javascript
{
 test: /\.(csv|tsv)$/,
 use: ["csv-loader"]
}
```

Now we can directly import the csv file in our code. In `src/main.js`, add in these two lines of code:

Import the csv file first:

```javascript
import CsvData from "./mycsv.csv";
```

Then, at the bottom of the file, add in `console.log(CsvData);`

Now, run `npm run dev`. Open your browser and watch in your console. You should see the csv contents logged.

## Protecting webpack Bundle Files

After building your app with webpack, if you open either one of the bundle files, you'll see that the whole logic of the code can easily be accessed. While this likely isn't a concern if you're building small projects, you should pay special attention if you're developing commercial web apps.

By reverse-engineering the application's source code, malicious actors may be able to abuse the app, tamper with the code, or even uncover important business logic (which is both a tendency and a concern [in the Enterprise](https://blog.jscrambler.com/enterprise-javascript-opportunities-threats-solutions/?utm_source=dev.to&utm_medium=referral)).

Webpack plugins like Uglify or webpack obfuscator only provide basic minification/obfuscation and can be quickly reversed with automated tools, and so fail to properly protect webpack bundle files. On the contrary, Jscrambler provides enterprise-grade [JavaScript protection](https://jscrambler.com/code-integrity?utm_source=dev.to&utm_medium=referral) which cannot be reversed by automated tools and provides several layers of security, not just obfuscation.

To use the Jscrambler webpack plugin, first you have to install it:

```bash
npm i --save-dev jscrambler-webpack-plugin
```

Then, in the `webpack.config.js` file, add this line:

```javascript
const JscramblerWebpack = require('jscrambler-webpack-plugin');
```

And finally add the Jscrambler plugin to the plugin array in the same `webpack.config.js` file:

```javascript
plugins: [
    new JscramblerWebpack({
      enable: true, // optional, defaults to true
      chunks: ['app', 'print'], // optional, defaults to all chunks
      params: [], 
      applicationTypes: {}
      // and other jscrambler configurations
    })
  ]
```

During the webpack build process, the Jscrambler client will use the `.jscramblerrc` config file. For more details, see the full [integration tutorial](https://blog.jscrambler.com/protectyourcodewhileusingwebpack/).

## Conclusion

By now, we have covered several aspects of webpack. It is a very dynamic script and asset management tool.

We have not used all of its features but these should be enough for your average application. For even more advanced tools, please refer to the official [webpack documentation](https://webpack.js.org/).

Originally published on the [Jscrambler Blog](https://blog.jscrambler.com/easy-custom-webpack-setup-for-react-js-applications/?utm_source=dev.to&utm_medium=referral) by Lamin Sanneh.