By Adeel Imran

This article has been outdated with the new release for babel, kindly check the updated article “How to combine Webpack 4 and Babel 7 to create a fantastic React app”, last updated October 13th, 2018

In this article, I’ll go through how to set up a React application using Webpack 4. By the end of this tutorial, you’ll know on how to hot reload your application every time you press **ctrl + s** in your editor of choice.

I use Visual Studio Code (VS Code), and I love it. It is light weight, flexible, and the best part is it’s free. I love free. If you haven’t tried it out, give it a try.

Our Goal

Our goal for this tutorial is to create a React app, with some cool features like async/await. I won’t be using react-router version 4 in this tutorial, because I mainly want to focus on how to play with Webpack.

So by the end of this article, you will be good at:

  • Setting up a development environment, with hot reloading using webpack-dev-server
  • Adding SCSS and HTML support in your code with webpack
  • Adding support for features like try/catch, async/await and rest operator
  • Creating a production build — optimized and ready for deployment
  • Setting up different environments in your code like stage, demo and production

Guys I am telling you that if Webpack seems a bit hard, after this that won’t be the case anymore.

Development Environment

Make the Folder

Make a folder called tutorial in your directory.

Create package.json

Open up your terminal, and go into the tutorial folder.

Type:

npm init -y

This will create a **package.json** file in your tutorial folder.

The file will look something like this:

Image This is what your package.json file will look like initially. I am using VS Code for the purpose of this tutorial

Create the index.js file

I’ll create a folder called **src** in my **tutorial** folder.

In the **src** folder, I’ll create a file called **index.js**.

Image and yeah, i’ll use star trek quotes a lot during this tutorial because IT’S AWESOME :D

Bundle the code

I know this isn’t much, but bear with me. Things will get interesting pretty soon.

Now in order to bundle our code, we need to set up some configurations so that Webpack can know where to bundle the code from. For that we need to install some dependencies.

So let’s start by typing:

npm i --save-dev webpack webpack-cli webpack-dev-server @babel/core @babel/preset-env @babel/preset-react @babel/preset-stage-2 babel-loader@^8.0.0-beta

WOW! I know that was a lot of dependencies. Let’s recap why we needed these in the first place.

webpack: We need Webpack to bundle our code.

webpack-cli: We will be using some CLI features for Webpack to make our life easier while writing some scripts.

webpack-dev-server: I will create a server using the webpack-dev-server package. This is only meant to be used in the development environment, and not for production. This means while developing and working on my code, I don’t need a separate server like Node.js.

@babel/preset-env: This package behaves exactly the same as @babel/preset-latest (or @babel/preset-es2015, @babel/preset-es2016, and @babel/preset-es2017 together). Cool right?

@babel/preset-react: The name of the package sounds clear — this will add support for react while we bundle our code.

@babel/preset-stage-2: This will add stage-2 feature of the Ecma TC39 proposal. You can read more about it here.

@babel/loader: This is a dependency of Webpack. It allows transpiling Babel using Webpack.

@babel/core: This is a dependency for the @babel/loader itself.

So now you know a little bit about what we installed and why.

Your package.json file should be looking something like this:

Image This is what your package.json file should be looking like right now.

Create a Babel file

We also need to add a new file called .babelrc , so let’s create it as well.

In your main folder directory, create a file .babelrc and the following code snippet. This will help Webpack when bundling your code and converting those Sassy codes that we will write.

Set up Webpack 4

Okay so the boring part has been done. Let’s move onto the main part of this tutorial: setting up Webpack 4.

To quote from Star Trek:

He tasks me. He tasks me; and I shall have him. I’ll chase him ’round the moons of Nibia and ’round the Antares maelstrom and ’round Perdition’s flames before I give him up.

So let’s create a new folder called **config** and inside that folder let’s create a file called **webpack.base.config.js**.

The reason I call this file .base is because this contains all the common features we will use in our development and different production environments. Changes in this one file will reflect in all environments. Again if this doesn’t make sense now, guys, bear with me for a couple more minutes. It will start making sense.

Without further waiting, in your config/webpack.base.config.js file write these lines of code:

The module.rules define the set of rules that Webpack will apply to certain file extensions.

In our rules array, we define a test that tells Webpack what extension to use. Here I am telling Webpack to apply a certain rule to only .js based files.

Next comes exclude. While bundling, I don’t want Webpack to transpile everything. This will become very slow, especially when I include my node_modules folder as well.

So I will exclude it using the exclude property in the rule set. The last one, which is the most important one, is the use.loader property. Here I give it the value of babel-loader. What babel-loader does is use our defined presets that we defined in our **.babelrc** file to transpile all files with a .js extension.

So far so good, yeah? We are more then halfway there…

Image Even Professor Snape Applauds You. Awesome work guys, we are almost there.

Also one more thing: Webpack 4 sets the **src** folder as the default entry point and the **dist** folder as the default output point of your bundled result. Cool, right?

Go into your **tutorial** folder and run this script. This will bundle all your code and run that code in the browser:

Adeel@Frodo MINGW64 ~/Desktop/article/tutorial$ node_modules/.bin/webpack-dev-server --mode development --config config/webpack.base.config.js --open --hot --history-api-fallback

The basis for this script is that it will combine all of our code in the **src** directory and run it on the browser at this address:

http://localhost:8080/

Image Hmm! That’s different. This gives an error: Cannot GET /

HTML

So when we ran the script it compiled and opened up the browser. Now it had the code that we wrote in our **index.js** file, but it didn’t have an .html file in which it could run it.

We need to add an html-webpack-plugin inside our **webpack.base.config.js** file, and an **index.html** file in our **src** directory.

First install the dependency for transpiling HTML with Webpack:

npm i --save-dev html-webpack-plugin

Your **package.json** file should look like this:

Now let’s add an HTML file in our **src** directory and name it **index.html**:

Our project directory should look like this now:

Image Our project directory, should look something like this

While we are at it, let’s add that html-webpack-plugin in our **webpack.base.config.js** file.

So we added something new to our webpack config file — did you notice? I am just messing with you. I know you did.

Image Good job guys, we’re almost done.

Now what does this plugin do? Well, it’s very simple. Plugins, put simply, add abilities to your Webpack. You can read more about them here.

Now I have added just this one plugin called html-webpack-plugin. The purpose of this plugin is very simple: it creates HTML files to serve your bundle file(s).

Ok so let’s run that script again (fingers crossed). “I hope no errors this time,” said every developer once.

Adeel@Frodo MINGW64 ~/Desktop/article/tutorial$ node_modules/.bin/webpack-dev-server --mode development --config config/webpack.base.config.js --open --hot --history-api-fallback

This will compile and open up your browser in the available default port. Mine is:

http://localhost:8080/

Image I simply clicked ctrl + shift + i this opened up the inspect element in my chrome browser

Blue part: The blue part is simply where I put in my meta tags and defined a title for the app.

Yellow part: The yellow part highlighted is the hard coded part that we wrote in our **index.html** file. This is where our future React app will reside.

Red Part: The part where I underlined in red is the most interesting part. We never wrote this in our index.html file, so where did it come from?

Webpack is very smart. It took that file in your **index.js** , bundled it all up nicely, and added it up all neatly in the file called **main.js** . Then it injected it in our **index.html** file. Super Cool!

Add React

Let’s add React and get the party going. For that, we need to install some dependencies.

Let’s start with:

npm i react react-dom --save

Now go in your **index.js** file and write:

Let’s run that script again:

Adeel@Frodo MINGW64 ~/Desktop/article/tutorial$ node_modules/.bin/webpack-dev-server --mode development --config config/webpack.base.config.js --open --hot --history-api-fallback

This will compile and open up your browser in the default port. Mine is:

http://localhost:8080/

Wow, did you see what opened in your browser? Yes! You did! Your first Webpack configured React app.

Now there is still loads of stuff to do. But man oh man. Good job!

Image This is our react app, running Yayyyy! :)

Now here is the fun part. Go in your **index.js** file and change the title to anything of your choice. Hit **ctrl + s** and check your browser. It automatically updated your content.

Cool, right?

Let’s Recap

We have added a development environment. We added hot module reloading. We added support for .js files with React code. In the next part, we’ll add SCSS support in our Webpack.

SCSS

For SCSS support, we need to add some more dependencies in our **package.json file**.

Install the following packages:

npm i --save-dev style-loader css-loader sass-loader node-sass extract-text-webpack-plugin@^4.0.0-beta.0

sass-loader: This plugin will help us compile SCSS to CSS.

node-sass: The sass-loader required node-sass as a peer dependency.

css-loader: The CSS loader interprets @import and url() like import/require() and will resolve them.

style-loader: Adds CSS to the DOM by injecting style tag.

extract-text-webpack-plugin: It moves all the required **.css** modules into a separate CSS file.

So your styles are no longer in-lined into the JavaScript bundle, but are in a separate CSS file (**styles.css**). If your total stylesheet volume is big, it will be faster because the CSS bundle is loaded in parallel to the JavaScript bundle.

Now that our dependencies have been installed, let’s make some changes to our Webpack config file.

Let’s understand what we did here first. In our module.rules we have added a new rule. What that rule does is apply some bundling to all **.scss** files. I hope that made sense. Inside our use , we tell it extract some information.

Let’s get a bit deeper, and I’ll try to make it as simple as I can.

{ fallback: "style-loader", use: "css-loader!sass-loader" }

Try reading this piece of code from bottom-to-top.

Get all SASS code — .scss — using sass-loader and then convert it into CSS code using css-loader. Then take all that CSS code and inject it into our DOM with the