loading...

React without create react app. Start building your react project like a professional

siradji profile image Siradji Awoual Updated on ・6 min read

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.
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

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

Yarn init -y

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

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

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

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

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

our project structure should look like this

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

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)

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]
}
]

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
})
}

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
})
]
}

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

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]

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>

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)

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)

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”

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”
}

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

Posted on by:

siradji profile

Siradji Awoual

@siradji

A full stack JavaScript Developer happily married to react and node. I am currently having an affair with golang. Love new technologies and a sucker for coffee.

Discussion

markdown guide
 

Why do you say "like a professional"? You're saying using CRA is not "professional"?

 

Yes like a professional. You can't use CRA for production apps.

Edit: The comment above is misleading and i apologize for that. You can use CRA in production, but for me, CRA is just a quick prototyping tool that i don't use in production.

 

The react and vue cli tools are both leveraged for more production apps than you can imagine

Yes that's true and i apologize for my misleading comment.

No sweat, we're all here to learn together. Keep the articles coming!

That's the spirit of the DEV community! Openly admitting our mistakes, apologizing, and learning from each other.

Technicals aside, you're all amazing people. Keep it up!

 

Please, elaborate.

I thought these CLI toolchains (Angular, React, Vue, all have them) not only eased app bootstrapping, but also ensured optimization and best practices.

Don't get me wrong, I understand there are genuine configuration-related reasons to build from scratch. I also believe we all should know how to build our apps without CLI aid, as it serves not only to understand the whole process, but to debug potential issues too.

However, I am truly curious about why you think CRA should not be used for production. Would you say this also applies to Vue and Angular?

You can use CRA for real-world apps, but for me and most people i work with, tend to stay away from CRA in production. The reason is its lack of flexibility. You can make it flexible by ejecting and adding your stuff, but why?

I still use CRA and most of my toy projects are built using CRA.

In my perspective, CRA is very useful for quick prototyping, but for production, i'd build it from scratch.

My comment is misleading and i apologize for that.

 

I do like your post a lot. But you're contradicting yourself. "You can't use CRA for production". Point taken. But then why "webpack-dev-server"? I understand your point completely, it just might send a wrong message.

Sorry for the contradiction Kevin. One thing about programming is that everyone has his preferences.
I don't use CRA for production but others do. My reasons include lack of flexibility, tons of unnecessary stuffs etc.
And let's be honest, how many real-world apps were built with CRA? Not that many.

Hot reload? Yarn start? Well, webpack-dev-server is actually what enables us to do that.

 
 

Thank you for the article. but your code snippets are completely confusing:
const HTMLplugin = require(‘html-webpack-plugin’) declared but later new HTMLwebpackplugin is used.

<html lang=”en”>
<head>
<title>React boilerplate</title>
</head>
<body>
<div id=’root’></div>

  • here single quotes and double quotes mixed And there is a lot of confusing quotes - import React from ‘react’

And finally this line - entry: path.join(__dirname, ‘src’ ‘index.js’), what is the path you are passing to the join? ‘src’ ‘index.js’ ???

 

Friend your project is sick of bad! If you work that way with clients, better dedicate yourself to study!