DEV Community

Cover image for Say Bye to create react app. Here's how to Build your react project from scratch with webpack and Babel.
Suraj Auwal
Suraj Auwal

Posted on • Updated on

Say Bye to create react app. Here's how to Build your react project from scratch with webpack and Babel.

The memory of my first react app is still fresh in my memory. I can remember how ridiculously easy it was to set up a new project. Oh! My beloved npx create-react-app myAwesomeApp.

But as I go deeper into front end Development, I learned that CRA has many limitations. Don't get me wrong, CRA is an amazing tool which I still use. But its lack of flexibility made me look for other alternatives.

There are different ways to set a react project without CRA, but in this article, I will show you how to set up a react project using webpack and Babel.

What is webpack and Babel?

Basically, webpack is a javascript bundler that bundles your static assets into one big file. Babel is a transcompiler that converts ES6 Javascript to an older version (typically, ES5) of javascript for compatibility on all browsers.

Even though I won't be going deep into the aforementioned tools, I really recommend that you checkout their respective docs before proceeding.

Let's get started!

I am a big fan of yarn, so that's what I will be using throughout this tutorial.

let's create and go into our project folder.

Mkdir react-boiler-plate
 Cd react-boiler-plate
Enter fullscreen mode Exit fullscreen mode

We'll be installing packages, so let's create a package.json file

Yarn init -y

Enter fullscreen mode Exit fullscreen mode

Running this will create a package.json file that will contain the info of our app and all its dependencies.

Before installing any package, let's start by laying the structure of our app. This of course will be simple, nothing complicated.

react-boiler-plate 
 public
 Src
 Package.json
Enter fullscreen mode Exit fullscreen mode

Here we have two empty folders and a package.json. Does this structure ring a bell? Yeah, we will be mimicking the structure of our beloved CRA.

Now let's add some packages. We'll start with the dependencies.

Yarn add react react-dom

Enter fullscreen mode Exit fullscreen mode

These packages are the only required dependencies

Let's install the dev dependencies. I will be breaking this into two parts— the webpack packages and the Babel package.


Yarn add --dev webpack webpack-cli webpack-dev-server html-webpack-plugin

Enter fullscreen mode Exit fullscreen mode

Tip: the --dev flag is similar to --save-dev in npm

Let's get over each package.

The first package is webpack for assets bundling, webpack-cli will let us use webpack cli. Remember

yarn start

or

npm start

in create-react-app ? Webpack-dev-server gives us a development server. It comes with many things include hot reloading, that's for later.

Let's move on to installing Babel.


Yarn add --dev @babel/core @babel/preset-react @babel/preset-env babel-loader style-loader css-loader

Enter fullscreen mode Exit fullscreen mode

So we've installed Babel preset for both react and the environment (browser), style loaders to handle the importation of our assets and Babel loader for our .js files.

Next, let's create two files in our root directory.

touch webpack.config.js .babelrc

Enter fullscreen mode Exit fullscreen mode

our project structure should look like this

-react-boiler-plate
  public
  src
  .babelrc
  webpack.config.js
  package.json
Enter fullscreen mode Exit fullscreen mode

In our webpack.config.js file, let add some code. There's lots of different ways to write your webpack config and it all depends on your preference. I will stick to my convention in this article.

First, we're gonna need to require two packages. One is the path Module that comes with node and the other one is html-webpack-plugin, the package we installed.

const path = require('path')
const HTMLplugin = require('html-webpack-plugin')

Enter fullscreen mode Exit fullscreen mode

Now let's set up our rules. This will be an array of objects. The objects is for each rule we want to set. In this project, there will be only two rules. You can add as many rules as you want depending on your needs and project.
This is one of the many reasons as to why I like webpack — flexibility.

const rules = [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader'

   }
},

{
test: /\.css$/,
exclude: /node_modules/,
use: ["style-loader", "css-loader"]
}


]

Enter fullscreen mode Exit fullscreen mode

The first object, We're telling webpack to use babel-loader on all .js files in our project, but we exclude the node_modules file.
This is also the case in the second object. We tell webpack to use our style loaders on our .css files.

Next let's export our config.

module.exports ={
entry: path.join(__dirname, 'src' 'index.js'),
Output: {
filename: 'bundle.js',
Path: path.resolve(__dirname, './build')

},
module: {rules},
plugins: [
    new HTMLwebpackplugin({
      template: './public/index.html'
    })
}
Enter fullscreen mode Exit fullscreen mode

Here, we specify our entry and output file. The entry file is not created yet, obviously. This file is similar to the index.js file in create-react-app.
The output file is where our bundled app will be created. We specify the name to bundle.js and the parent folder to build.

The module key is where we set our rules. I see many people put their rules hers, but i like to just put it in a constant and then call it here. It makes everything cleaner.
Since we have already done that we can just do

module:{rules: rules} or module:{rules} (ES6)

.

Lastly, the plugins key contains an array of all the plugins we want to use. There are many plugins which you can use in your projects. Here is a list of some.

Our webpack.config.js file should look like this:


const path = require('path')

const HTMLplugin = require('html-webpack-plugin')

const rules = [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader'

   }
},

{
test: /\.css$/,
exclude: /node_modules/,
use: ["style-loader", "css-loader"]
}


]

module.exports ={
entry: path.join(__dirname, 'src' 'index.js'),
Output: {
filename: 'bundle.js',
Path: path.resolve(__dirname, './build')

},
module: {rules},
plugins: [
    new HTMLwebpackplugin({
      template: './public/index.html'
    })
]
}

Enter fullscreen mode Exit fullscreen mode

Before we forget, let's create the files we specified above. The index.html in the public folder and the index.js file in the src folder.

Our project structure should look like this:

— react-boiler-plate
 public
   index.html
 src
   index.js
 .babelrc
 webpack.config.js
 package.json

Enter fullscreen mode Exit fullscreen mode

Next, Let's configure babel. In our .babelrc file, add the presets we installed earlier. The content of this file should be in JSON format.


"presets"["@babel/preset-env","@babel/preset-react"]

Enter fullscreen mode Exit fullscreen mode

We have finished setting up our react project — well, 90% of it. In our index.html file, let's add a simple html boilerplate. if you are using vscode, type the exclamation mark and press enter. This will auto generate a HTML document for you. Then add an empty div with the ID of root and save.

Our index.html should look like this

<!DOCTYPE html>
<html lang="en">
<head>
    <title>React boilerplate</title>
</head>
<body>
    <div id='root'></div>
</body>
</html>

Enter fullscreen mode Exit fullscreen mode

Next, let's go to our index.js file in the SRC folder. First we need to

Import React and ReactDom. After that, Let's create a constant that will store the div that we created in our index.html file.
Our file should look like this:

import React from 'react'
import ReactDom from 'react-dom'

const  root  = document.getElementById('root')
Enter fullscreen mode Exit fullscreen mode

In the index.js file, let's create a functional component called app and wrap up.

Now our index.js should look like this:


import React from 'react'
import ReactDom from 'react-dom'

const  root  = document.getElementById('root')

const App = () => {
return (
<h1>Hello from React</h1>
)

} 


ReactDom.render(<App />, root)

Enter fullscreen mode Exit fullscreen mode

Voila! our react project is completed — mostly.

Remember how we use to start a dev server and build our app in a create-react project?

yarn start


yarn build

webpack-dev-server is an amazing tool that let us do just that. we can create our script, customize how our server should run, also offers hot reloading. You can check out the official documentation here

So let's head to package.json to set up our scripts. Since we won't be doing any testing and ejecting, we only need two scripts for this projects — start to start the dev server and build to compile our app.

In the package.json file, add a new key,scripts, with an object value. Inside the object, add the following code.

"start": "webpack-dev-server --mode development  --open --hot",
 "build": "webpack --mode production"

Enter fullscreen mode Exit fullscreen mode

What we added in the package.json file should look like this:

"scripts": {
    "start": "webpack-dev-server --mode development  --open --hot",
    "build": "webpack --mode production"
  }
Enter fullscreen mode Exit fullscreen mode

save and exit.

Voila!

Our react project is now complete.

yarn start

will start the development server. And if everything is okay, We should see a "hello from react in our" browser.

I know that is a long one, perhaps too long. you can use this as a boilerplate for all your react projects. You can also customize it and add more functionalities and rules.

If you're relatively new to webpack, i recommend you to learn more about it. It's a handy tool that you can't live without it (at least in my case).

The whole project is available on my github repo. You can check it out here

Oldest comments (1)

Collapse
 
mohsin708961 profile image
{{7*7}}

Awesome