Creating your React project from scratch without create-react-app: The Complete Guide.

underscorecode

_CODE

Posted on June 5, 2021

Creating your React project from scratch without create-react-app: The Complete Guide.

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.

mkdir my-react-project
Enter fullscreen mode Exit fullscreen mode

Once created, we're going to navigate into it.

cd my-react-project
Enter fullscreen mode Exit fullscreen mode

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.

npm -v
Enter fullscreen mode Exit fullscreen mode
node -v
Enter fullscreen mode Exit fullscreen mode

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

npm init
Enter fullscreen mode Exit fullscreen mode

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:

npm init -y
Enter fullscreen mode Exit fullscreen mode

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

{
  "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"
}
Enter fullscreen mode Exit fullscreen mode

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.

npm install react react-dom react-router-dom
Enter fullscreen mode Exit fullscreen mode

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.

npm install --save-dev webpack webpack-cli
Enter fullscreen mode Exit fullscreen mode

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.

npm install --save-dev @babel/core @babel/preset-react
Enter fullscreen mode Exit fullscreen mode

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:

touch .babelrc
Enter fullscreen mode Exit fullscreen mode

Then, just add the following code snippet:

.babelrc

{
  "presets": [
    "@babel/preset-react"
  ]
}
Enter fullscreen mode Exit fullscreen mode

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

npm install --save-dev babel-loader html-loader style-loader css-loader sass-loader
Enter fullscreen mode Exit fullscreen mode

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.

npm install express
Enter fullscreen mode Exit fullscreen mode
npm install --save-dev nodemon
Enter fullscreen mode Exit fullscreen mode

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:

touch webpack.config.js
Enter fullscreen mode Exit fullscreen mode

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

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"
    }),
  ]
}
Enter fullscreen mode Exit fullscreen mode

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

<!DOCTYPE html>
<html>
  <head>
    <title>My React App</title>
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

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.

touch app.js
Enter fullscreen mode Exit fullscreen mode

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

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);
      }
   });
});
Enter fullscreen mode Exit fullscreen mode

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

import React from "react";

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

export default App;
Enter fullscreen mode Exit fullscreen mode

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

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"));
Enter fullscreen mode Exit fullscreen mode

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:

{
  ...
    "scripts": {
      "test": "echo \"Error: no test specified\" && exit 1",
    }
  ...
}
Enter fullscreen mode Exit fullscreen mode

Now, we're going to add a couple more: run and build, like this:

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

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.

npm run build
Enter fullscreen mode Exit fullscreen mode

And then, just run it.

npm run dev
Enter fullscreen mode Exit fullscreen mode

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 and Twitter for more related content.

šŸ’– šŸ’Ŗ šŸ™… šŸš©
underscorecode
_CODE

Posted on June 5, 2021

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related