Creating your React project from scratch without create-react-app: The Complete Guide.
Tags: react, webdev, javascript, webpack
Published: 2021-06-05 13:06:56

Creating and setting up your own React project from scratch can be, at times, a little bit tricky, even though it's not your first time starting a React project. That's why we have __create-react-app__, a command that prepares and installs all the boilerplate for us and have our application ready to rock from the very first moment after the process finishes.

But, even though create-react-app is a very good choice to start off with, specially for those who are new to the React world or who just don't want to spend time setting up everything, it's interesting to know that there's another way to get things done. 

As you can imagine, this method is not going to be as easy as just running a command, but it will surely be way more satisfactory and useful for your developer career (not to mention that it's a reusable process and you'll get rid of not-that-necessary stuff that comes together with create-react-app and that will overload your project).

Note that I won't be using a specific structure for the project because I think that's very personal and every developer works in a different way, so, I leave that choice up to you 😉

So, with all this said, let's dive into it!

##Step 1: Creating the folder that will host our project
We're going to start by creating a new directory for our project at a location of our choice.

```bash
mkdir my-react-project
```
Once created, we're going to navigate into it.
```bash
cd my-react-project
```

##Step 2: Initializing the project

To initialize our project, we're going to run a __npm__ command. 

_npm_ is a package, version and dependencies manager made for JavaScript. If you haven't installed npm yet, you need to directly install __Node.js__, since they work together and npm is included in Node.js installation as well. Node.js will let us execute JavaScript on server side.

>You can perfectly use a different package manager, like _Yarn_ or _Bower_.

If you're not sure if you have previously installed npm/ Node.js, just run the following commands to check the last versions installed for them. If these commands return a version number, then you already have them on your computer. Otherwise, you'll need to install them again.
```bash
npm -v
```
```bash
node -v
```

Once we have npm and Node.js ready to use on our computer, we're going to run the following command:

```bash
npm init
```

This command will create a __package.json__ file, which is the file where all the dependencies and scripts for our project will be specified.

Throughout the process of the file creation, the terminal will pop up some questions to let you set up your project with proper information about it. If you want to skip the current question, just press enter to jump onto the next one.

If you don't feel like giving extra information for the project or just want to configure it later, just add the __-y__ flag to the command:

```bash
npm init -y
```

Once the installation is done, we'll have a new package.json file in our project that will look like this:

```json
{
  "name": "my-react-project",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}
```

##Step 3: Installing dependencies
We also need to install a few dependencies manually in order for our future React application to work properly and as expected.

###React dependencies
We'll be installing the following dependencies on React's side:

__`react`:__ the JavaScript library we'll be working with.
__`react-dom`:__ package with some methods to manage DOM elements.
__`react-router-dom`:__ package that contains the DOM bindings for React Router.
```bash
npm install react react-dom react-router-dom
```

###Webpack dependencies
We'll also need a module _bundler_ to get our project ready for the web. __Webpack__ bundles all the JavaScript files in your project and prepares all the necessary resources for usage in the browser.

As we only need Webpack to work in the development environment, we're going to install all its related dependencies adding the flag _--save-dev_ or simply _-D_ to the command.

We'll be installing the following dependencies on Webpack's side: 

__`webpack`:__ the bundler.
__`webpack-cli`:__ CLI for Webpack.

```bash
npm install --save-dev webpack webpack-cli
```

###Babel dependencies
Babel is a JavaScript compiler that converts (or _transpiles_) JavaScript ES6 to JavaScript ES5 since not all browsers currently support ECMAScript 6 features.

The Babel-related dependencies we're going to install are the following:

__`@babel/core`:__ Babel compiler core.
__`@babel/preset-react`:__ package that contains a set of plugins used to support React features.

```bash
npm install --save-dev @babel/core @babel/preset-react
```
Before going further on dependencies, we're going to configure Babel in our project in order for our JavaScript files to be transpiled as intended.

Let's go back to the terminal to create a new file for this configuration:

```bash
touch .babelrc
```
Then, just add the following code snippet:

`.babelrc`
```json
{
  "presets": [
    "@babel/preset-react"
  ]
}
```
###Loaders for Webpack
Webpack needs something called __loaders__ to preprocess files. They are useful to bundle static resources beyond JavaScript.

These will be the basic loaders we'll be working with:

__`babel-loader`__: loader for Babel.
__`html-loader`__: loader for HTML.
__`style-loader`__: loader that injects styles into the DOM.
__`css-loader`__: loader for CSS.
__`sass-loader(*)`__: loader for SASS/SCSS.

(*) This loader is not strictly necessary, but in case you want to use a CSS preprocessor, you'll need a loader for it as well. There also exists loaders for LESS, PostCSS, Stylus...

```bash
npm install --save-dev babel-loader html-loader style-loader css-loader sass-loader
```
###Webpack plugins
We also need Webpack plugins that will help for bundling purposes.

__`html-webpack-plugin`__: this plugin is used to create HTML files that will serve bundles.

__Note:__ Since we're working in a development environment, we'll just be using a loader for styles, but for production builds, it' recommended to extract the CSS from the bundle using _MiniCssExtractPlugin_. This plugin extracts CSS into separate files and creates files for every JavaScript file which contains CSS.

The loader is faster and will set the styles as internal, inside the `<style>` tag, while the plugin will link the external styles file to the HTML document using the `<link>` tag.

###Server dependencies
Our app will also need a server, so we'll be using server-related dependencies as well. We're going to install the following:

__`express`__: Node.js framework that we'll be using to create our server file and to handle server requests. 
__`nodemon`__: tool that will refresh our web app whenever a  change occurs in the app directory.

```bash
npm install express
```

```bash
npm install --save-dev nodemon
```

##Step 4: Configuring Webpack

Next step is putting Webpack's loaders and plugins we just installed together in a config file to let it know how its behavior should be in the bundle process of our files.

To start with, we're going to create an empty file for this purpose. Back on the terminal:

```bash
touch webpack.config.js
```

Before diving into the content of this config file, we're going to see what it really does and how it behaves.

First off, we need to tell Webpack which the __entry point__ for our app will be. This entry point will be a JavaScript file called __index.js__.

We also need to specify the __output file__, which will be the final JavaScript file all bundled and the only one that will be referenced explicitly from the HTML file served.

At this point, it's important to mention the __dist__ folder. This folder is a directory created as part of the bundling process and will hold all the static files generated as a result of it.

More stuff Webpack needs to know is the type of files it'll be working with to _translate_ them properly. For the moment, those types are JavaScript, HTML, CSS and SASS/SCSS. But, if in the future we need to work with more different kind of files (and we definitely will), such __images__, __fonts__, etc, these will need their own loaders as well.

And finally, we also need to configure the necessary plugins. In this case, _HtmlWebpackPlugin_, which will generate the HTML that will be served to the browser.

`webpack.config.js`

```javascript
const path = require("path");
const webpack = require("webpack");
const HTMLWebpackPlugin = require("html-webpack-plugin");

module.exports = {
  entry: "./index.js",
  output: {
    filename: "bundle.js",
    path: path.resolve("dist"),
    publicPath: "/",
  },
  module: {
    rules:[
      {
        test: /\.(js|jsx)$/,
        exclude: /node_modules/,
        use: "babel-loader"
      },
      {
        test: /\.html$/,
        use: "html-loader"
      },
      /*Choose only one of the following two: if you're using 
      plain CSS, use the first one, and if you're using a
      preprocessor, in this case SASS, use the second one*/
      {
        test: /\.css$/,
        use: ["style-loader", "css-loader"],
      },
      {
        test: /\.scss$/,
        use:[
          "style-loader",
          "css-loader",
          "sass-loader"
        ],
      },
    ], 
  },  
  plugins: [
    new HTMLWebpackPlugin({
      template: "index.html"
    }),
  ]
}
```

##Step 5: Creating the HTML template
Well, this is the simplest step but still we need to take it 🙂

We need to create a basic HTML document that will be used by _HTMLWebpackPlugin_ as a template to generate the new one. As easy as that.
`index.html`
```html
<!DOCTYPE html>
<html>
  <head>
    <title>My React App</title>
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>
```
Pay attention to the empty `<div>` with id _root_. We'll learn about it later.
 
##Step 6: Creating the server

The __server__ is going to be a new JavaScript file that will open up a port to listen on, do a little bit more of configuration and make a few requests.
```bash
touch app.js
```
We're going to call it __app.js__ but you can give it any name of your choice. Just be careful with capitalization. You'll understand why later.

`app.js`

```javascript
const express = require("express");
const app = express();
const path = require("path");
const port = process.env.PORT || 3000;

app.listen(port, () => {
   console.log(`The app server is running on port: ${port}`);
});

const DIST_DIR = path.join(__dirname, "dist");
const HTML_FILE = path.join(DIST_DIR, "index.html");

app.use(express.json());
app.use(express.static("public"));
app.use(express.static("dist"));

app.get("/", (req, res) => {
   res.sendFile(HTML_FILE, function(err){
      if(err){
         res.status(500).send(err);
      }
   });
});
```
What we are doing in this file is starting a new server that listens on port 3000 for connections. Then, the HTML file generated by Webpack is sent to the root URL (in other words, this HTML will be the homepage of our app). We're also indicating that every file in the directories _public_ and _dist_ will be static and should be treated as such.

##Step 7: Creating the React app
Now, we're going to create __App.js__, which will be the main component of our React app (capitalization alert here!).

`App.js`
```jsx
import React from "react";

const App = () => {
   return <div>Hello, World!</div>;
};

export default App;
```
The render of this component will be injected into the served HTML, so what we'll see when we open up the browser will be _Hello, World!_.

Let's take a look at how we can do this.

##Step 8: Creating the entry point for the React app
In this step, we're going to specify the routing for our app and also, where in the DOM the content from React should be inserted.

`index.js`

```jsx
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";

import App from "./App.js";
import "./styles.scss";

const appRouting = (
  <Router>
    <Switch>
      <Route exact path="/" component={App} />
    </Switch>
  </Router>
);

ReactDOM.render(appRouting, document.getElementById("root"));
```

We're just indicating that the _App_ component should be rendered when the URL matches the root path exactly, and that the render content should be placed inside the tag with id _root_ in the index document.

##Step 9: Defining the scripts
And, finally, we're going to set up the __scripts__ to be able to build and run our app. 

Back in _package.json_, we initially had something like this in the scripts section:

```json
{
  ...
    "scripts": {
      "test": "echo \"Error: no test specified\" && exit 1",
    }
  ...
}
```
Now, we're going to add a couple more: _run_ and _build_, like this:

```json
{
  ...
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "rm -rf dist && webpack --mode development",
    "dev": "nodemon app.js"
  ...
}
```

##Step 10: Building and running our app
Last step is (finally) building and running our app.

We first need to run a build command to bundle everything. 

```bash
npm run build
```

And then, just run it.

```bash
npm run dev
```
Our app is now available at: __`localhost:3000`__.

___

And... that's it! Now we have our React application ready to start working with it 🙌🏼

If you've reached this point, thank you very much. I hope that this tutorial has been helpful for you and I'll see you all in the next.
___

🎉 Don't forget to follow me on [Instagram](https://instagram.com/underscorecode) and [Twitter](https://twitter.com/underscorecode) for more related content.