Webpack, Babel, and React from Scratch — BUT WHY? by@jsphbtst

Webpack, Babel, and React from Scratch — BUT WHY?

Joseph J. Bautista HackerNoon profile picture

Joseph J. Bautista


In between graduate school and other things, I have been digging deeper into the JavaScript ecosystem. As a person who loves React, I got curious with create-react-app. With a simple npm install -g create-react-app on your command line, you will be able to install the most popular React starter pack. However, have you ever wondered how create-react-app works? Or how they make these apps run fast on the browser with relatively smaller network requests? Maybe perhaps how bundling and generating static files happens after running npm run build? These things are intriguing. Under the veil of magic these open source projects carry are simple lines of code that you and I can learn and understand.

I decided to build a React application from scratch with the help of webpack and babel and deployed it to Netlify. You can check out my GitHub repo here. I’ve also deployed the static site to Netlify here.

For this project we’re going to make a simple React application that changes the background color of the webpage via button clicks. Start imagining in your head how that would look like. Would we need a class-based component or a functional component? What would onClick do? Would you need state?

As you’re mulling over those things, it’s time to set up webpack and babel. Make sure you have Node installed on your machine and follow the commands below. This would include creating a new folder named react-webpack-simple — or whatever you want really — and run npm init. Proceed to then install the libraries listed below.

mkdir react-webpack-simple
cd react-webpack-simple
npm init
npm install --save-dev @babel/core @babel/preset-env @babel/preset-react babel-loader
mkdir src
cd src
touch index.html index.js
cd ..

Babel-core is used to convert ES2015+ code into a backwards compatible version of JavaScript. @babel/preset-env and @babel/preset-react, on the other hand, are a set of plugins to support Babel and React features respectively — they do a lot of heavy lifting in the background for us. Lastly, Babel-loader transpiles our JavaScript code given all the presets we’ve laid out.

Go to the root of your directory, in our case, react-webpack-simple, and create a file called .babelrc. This is the file where we will define all the presets that Babel will use. As was mentioned above, that’s @babel/preset-env and @babel/preset-react.


Great! We’re inching our way towards finishing the hardest part of this project — trust me, React’s the easy part. Now create a new file called webpack.config.js in the root folder. This is the configuration file of Webpack. Remember, at the heart of it, Webpack is just a module bundler. Different projects have different goals in mind, which necessitate different types of ways to serve files in production. Do we wants the css file to be in one style tag in our main html file? Do we want to enable caching? This is where all the magic happens.

But first, webpack has some core concepts that you need to familiarize yourself with — you can read about them in the docs. Entry, as the name implies, is the entry point for webpack to begin building its internal dependency graph. Anything not imported, in our case, in ./src/index.js will not be a part of that graph. Make sure your JavaScript files and others are imported properly. The output, on the other hand, is where webpack will dump all of the bundles it creates. Since webpack can only understand JavaScript or JSON, there has to be functions or “middlewares” out there to help webpack understand things like static images, css files, and others. These “middlewares” are defined in loaders, webpack will use these “middlewares” to understand these non-JavaScript and JSON files in order for it to properly put these files in the internal dependency graph. Lastly, plugins help out loaders by helping out in the bundling process, asset management, and others.

// Install these dependencies before writing webpack.config.js
npm install --save-dev html-webpack-plugin mini-css-extract-plugin react react-dom

The webpack.config.js file below is the application of theory from above. VENDOR_LIBS contains all the libraries we need in our react application. We’re creating this array because we don’t want to load all of our libraries right off the bat — that would eat up network requests. Instead, it would be better if we load these libraries on-demand.

The [name].[chunkhash].bundle.js format that you see is for caching purposes. To increase user experience, we wouldn’t want our users to keep on downloading the dependencies used in our applications every time they load up our site. If said dependencies were somehow cached, then loading up a website would be faster per visit as our user would have already downloaded those dependencies in the past. If we make updates, then the user would only have to download the new versions, and not everything all over again.


In the modules section, babel-loader is used to transpile the JavaScript code. Remember what I said about non-JavaScript code? HTML and CSS files are non-JavaScript, so html-loader and css-loader are used to help with those. The test just means that if a file ends in [insert extension here], webpack will use [insert loader here]. For example, if a file ends in html, webpack will use html-loader.

In the plugins section, HtmlWebpackPlugin is used for importing JavaScript files from the HTML document — it’d be cumbersome to manually update the names of the script tags (with those hashed values mind you) every time you build the project. Meanwhile, the MiniCssExtractPlugin is used to generate separate CSS files per JavaScript file that imports one. Lastly, webpack.DefinePlugin is used to prepare our project for production — React behaves differently in production vs. development.

Still with me? The last webpack configuration we have to do is to download rimraf and webpack-dev-server using npm. rimraf is a library that will enable us to delete our previous build files and replace them with new ones. This way, we don’t clutter our workspace with both old build files and new build files — it becomes confusing that way. webpack-dev-server is used for development purposes as every code change will automatically refresh the browser, making development easier, as opposed to building your project every time and opening index.html every so often. Also modify the scripts of your package.json into the following below. npm run build will create the build files while npm run start will start the development server.

// Don't forget to run npm install --save-dev rimraf webpack-dev-server first
"scripts": {
"clean": "rimraf dist",
"start": "webpack-dev-server --open --mode development",
"build": "NODE_ENV=production npm run clean && webpack -p"

After all of that tinkering, your folder structure should look something like this. Note that the dist folder contains our build files. This folder is automatically generated when we enter the npm run build command.

Your folder structure

It’s pretty straightforward from here on out. index.html contains the following code:

If you’ve ever used create-react-app before, the div tag with a root id should look familiar. Note that this post isn’t about learning React, as I assume you already know how to use said framework. Below is the React code we will be using. It uses Bootstrap 3 and renders four buttons on the DOM, with each button corresponding to a different background color change.

That was a long process but it was worth the effort! Go to the terminal, enter npm run build, drag and drop your index.html file in the dist folder to your preferred web browser, and you should be good! I deployed my project in Netlify, as was stated above in this blog post, which allowed me to just drag and drop my static files in the dist folder, wait a couple seconds, and see it get deployed.

Going forward, I’ll be building more applications from scratch like this to study all the things that are happening under the hood. What we built here is a static website that uses no back end server. The next project I’ll be building will include a Node back end and perhaps sockets to make it real time. The process of iterating means adding more features, but also means researching more to understand what the hell I’m doing. Learning never stops.


Signup or Login to Join the Discussion


Related Stories