A tutorial application build from scratch

Usage no npm install needed!

<script type="module">
  import reactFromScratch from '';


React from Scratch

Welcome! This will be a tutorial to help you (and me) learn how to creation an application in React from scratch. You may be wondering why you even want to create a React application from scratch when tools like create-react-app exist and make creating an application a breeze. Well, the answer is you wouldn't; nine times out of ten you will just use some template like the create-react-app command to build your application and get programming right away. The benefit to creating the app from scratch is the knowledge gained along the way.

If you rely on create-react-app entirely and never make any modifications to the pre-populated files and configurations, then it will be all the more difficult to make those modifications later in the application's lifespan, since you won't deeply understand where the configurations are located, what options you need to change, and what those effects may be.

Thus, the focus of this guide is on helping you understand the ins-and-outs of React, Babel, and Webpack. I'll also do my best to provide some additional tips on Git. Throughout the tutorial, you will (ideally) be able to follow along with my build process simply by viewing the commit history. I will make the best effort to keep the commit history aligned with the progress of this README file, so you can view the process step-by-step, commit-by-commit.

Finally, the ulterior motive behind this tutorial is to better teach myself these concepts. I am by no means a React expert. I started programming in React earlier this year and have made a random assortment of apps in various degrees of complexity, with each (hopefully) being better built than the last. By the end of this tutorial, I hope both you and I are better developers from it.

If you're an experienced React developer and you come across this, please feel free to read through or follow along, and if you notice any issues, please create a pull request and correct the misstep! As a community we can create the greatest version of this tutorial that we can.


The "goal" of this application will be to create a simple one-person Black Jack game. If you don't know the rules of Black Jack, you can read them anywhere online or at Bicycle's website. Essentially, we have a deck of 52 cards and the goal of the player is to get as close to 21 points (2 being 2 points, 7 being 7 points, etc.) as possible. The rules of the game aren't particularly important, since by the time we get to implementing those, we will have already passed the core concepts we need to cover. But, in my opinion it is worth having an end goal in mind from the start. It will lead to a better process in the end.

What you should have installed:

  • NodeJS (and npm)
  • Git
  • A shell (this can be Git Bash, WSL, Terminal, PowerShell, or whatever you are most comfortable with)

If you aren't already comfortable with a shell, then you should be. I know you can get by just fine without it, I did for years, but I truly believe the main advantage to using shells isn't the script-ability or control you get, but the deeper understanding you get from running the commands yourself. By using Git in the command line you gain a deeper understanding of what your GUI utilities are doing in the background. Plus, it's going to be pretty difficult finding good GUI applications for npm.

If you need a shell for Windows (Mac and Linux users have a great one already built in), then I'd recommend Git Bash; if you have installed Git to your machine already (which you should before you start this tutorial), then it is likely already installed on your machine. Just launch the application using the start menu and it will be well configured already. This is a great starting point for most developers; it is easy to set up, and the commands are mostly the same as Linux. If you are looking to get more advanced, check out Windows Subsystem for Linux, it is essentially a Linux machine running in your Windows machine like a little Russian doll, and so far I have nothing but good things to say about it. However, it does come with a little more overhead of installation than Git Bash. Whichever you choose, just be comfortable using the basic commands and you'll be set.

Part 1: Setting Up Our Files


This will be one of the more brief chapters, since I will make a lot of assumptions about your prior knowledge here. There are a few things I will stress that may seem simple to many people, but I have found myself glancing over them in the past.

To start off, we need to create the Git repository that we will be tracking our changes. By now, I have already created the repository on my local machine, but I will walk you through the general steps now.

First step of the journey, create a directory to store our repository and enter it

mkdir react-from-scratch
cd react-from-scratch

Next, we'll initialize our Git repository using the simple command git init. This will create the necessary .git directory and begin tracking our changes. At this point, if you were to try to run the command git push, Git would complain that there is no upstream repository to push to; this is because we haven't configured one yet. Go to your favorite Git management site (GitHub, Bitbucket, GitLab, etc.) and create a repository. Then, you can run the commands to add a repository

git remote add origin {url-to-repo}
git fetch
git checkout {main/master}

The first command can be broken down into three parts; git remote narrows down our git command to the "remote" management section of our Git repo. You can have multiple remote repositories, but it's generally uncommon. Most of the time you will have a single remote, which by convention is named "origin". Thus that's what the next part of the command is doing, add origin. We are telling git to add a remote repository and name it origin. Finally, the last part will be the URL to repository; this URL is generally located by clicking a "Clone" button somewhere on your site.

Second, we'll fetch the current branches from that remote repository. This is mainly just to get the main or master branch (GitHub recently changed its default branch name to main instead of master. You can read more about that decision here) so we can seamlessly push our changes to it without having any conflicts. We'll ensure we are on that branch by running the last command git checkout main, which will ensure all our new changes are made on the main branch. Normally, you'd want to make you changes on a separate branch every time, or at least on a dev branch of some sort, but since this is a demo application, we'll stick with main for our convenience.

Finally, to wrap up our Git configuration, we'll create a .gitignore file and add a few entires to it:

touch .gitignore

We can stop there for now, but we'll be adding entries to the .gitignore file as we go along. We could add them all now at the beginning, or use a template, but I prefer to build my .gitignore gradually in this case since it will keep the rubber cloest to the road.

Add your changes using git add ., then commit them using git commit -m "Message goes here". I won't list these commands again, from here on out I'll just say "commit our changes" or something to that effect.

We're now ready to initialize npm.

Setting up npm

Next, we need to initialize our project as an npm project. This is done very similiarly to Git, by running an init command

npm init

You will be asked a series of questions by the setup command, and you should know all the answers before you have even started programming. If you want a more in-depth walkthrough, checkout out the offical docs or the offical NodeJS guide, both are great resources. I will go through the basics here now, but you'll find the answer to most of these will be "we don't care" since this is a demo application, but they will be very important if you ever decide to contribute to the npm ecosystem.

  1. Package Name - Must be all lowercase and only use '_' and '-' characters. You probably won't need to fret about this too much, this name would be displayed if we were going to upload our package to a public library somewhere, but we aren't in this case, so it's not a huge bother. I named mine "react-from-scratch" to match my directory name
  2. Version - Can be any version based on sementic versioning. I generally go for 0.0.0 but the default is 1.0.0. Either is fine, choose whichever you prefer
  3. Description - A description of your application. This is again only useful if you are uploading your product somewhere, but we aren't, so type in a brief description (or don't, up to you)
  4. Entry Point - The entry point into your application. Another field we won't use, it defines which file will be read when a user of your library imports your code like const libary = require("library-name");. This line tells require which file to read and the exports object will be the resulting variable. We won't really use this, since this will be a web application and shouldn't be imported anywhere. We can remove this later
  5. Test Command - This command will become your npm test command, and is generally important because it will be used by both developers and the CI/CD process. We won't focus on tests, so we will just remove this option once we're done with our first-time setup. It's OK to leave this one blank
  6. Git Repository - npm is smart enough to detect if you are creating a project with an existing Git repository based on your .git folder. If you have that properly configured, then the default answer should be acceptable, otherwise grab the web url for your repo and enter it here
  7. Keywords - Could also be known as "tags" they allow users to better search for your library on package repositories like npm; since we won't be uploading ours anywhere, it can be ignored
  8. Author - You. Generally you want to enter in the format "FirstName LastName (, but there are a few other ways you could configure it, checkout out the official docs for more details. Both the email and homepage are optional, but you should at least specify a name. Again, this is mostly done for package repositories like npm
  9. License - The type of open source license you'd like to use. If you need help with this, check out which can give you some guidance. I'll be using an MIT license for this demo

And we're finally done; npm will generate a package.json file with the configurations we listed and we're off to the races. But before we move on, let's dive into what just happened a little more.

By running the npm init command, we didn't really do anything special. All that happened was we were prompted with a series of basic questions to populate a package.json file. And that's it; unlike Git, there is no secret directory that you need to worry about, there's not .npm file created, no hashes no encryption, no nothing. The npm init commands simply helps you create a basic package.json file.

The package.json file

There are no requirements for the package.json file besides it being valid JSON. {} is a valid package.json file. If we really wanted, we could create a valid package.json file by simply running echo "{}" > package.json instead; we aren't required to put any fields at all. Most will be ignored if you aren't uploading your application anywhere. So, for our example, let's do a little bit of cleanup. I want to distill our package.json down a bit, so I'll remove the test script and the main entrypoint. They won't be necessary, but I'll keep the remaining fields just as a description since this will be a public tutorial.

I will add one more critical field, however, and that is the private: true property. This will prevent us from accidentally uploading our demo package to npm's online library. Checkout out the Publishing a Package section below for more details, but I'll consider that to be optional.

The main purpose of the package.json for our application is listing all the packages we have installed. //TODO list dependencies sections

Publishing a Package

In order to publish a package to npm, you utilize the npm publish command; you can even test it out by running the npm publish --dry-run command to see what the outcome would be. This gives you so useful information, including the total size of your application, if I run it on the project as it stands now, I'm given the following result

~/dev/react-from-scratch (main)$ npm publish --dry-run
npm notice
npm notice 📦  react-from-scratch@1.0.0
npm notice === Tarball Contents ===
npm notice 1.1kB LICENSE
npm notice 523B  package.json
npm notice 7.5kB
npm notice === Tarball Details ===
npm notice name:          react-from-scratch
npm notice version:       1.0.0
npm notice package size:  4.3 kB
npm notice unpacked size: 9.1 kB
npm notice shasum:        7134117608a9a60ea7f81fbd51775883b50343a5
npm notice integrity:     sha512-AooFG5y6mk1yy[...]0mv/pdYk4ASuQ==
npm notice total files:   3
npm notice
+ react-from-scratch@1.0.0

Notice that it gives me the package size and the unpacked size; many packages take great pride in the fact that their packages have a low memory footprint, and I tend to agree that it is an admirable metric to aim for.

Without the private set to false, if we run the command without --dry-run set, you will most likely get a failure message still; there are a few other steps you'll need to perform in order to ship your package. But if you set private to true, then you will be stopped even earlier by a different error message altogether; however you will still get the same statistics as you did after running the dry run command.

~/dev/react-from-scratch (main)$ npm publish
npm notice
npm notice 📦  react-from-scratch@1.0.0
npm notice === Tarball Contents ===
npm notice 1.1kB LICENSE
npm notice 523B  package.json
npm notice 7.5kB
npm notice === Tarball Details ===
npm notice name:          react-from-scratch
npm notice version:       1.0.0
npm notice package size:  4.3 kB
npm notice unpacked size: 9.1 kB
npm notice shasum:        7134117608a9a60ea7f81fbd51775883b50343a5
npm notice integrity:     sha512-AooFG5y6mk1yy[...]0mv/pdYk4ASuQ==
npm notice total files:   3
npm notice
npm ERR! code EPRIVATE
npm ERR! This package has been marked as private
npm ERR! Remove the 'private' field from the package.json to publish it.

npm ERR! A complete log of this run can be found in:
npm ERR!     /home/me/.npm/_logs/2020-12-26T14_37_32_888Z-debug.log

Notice the section at the bottom that states "this package has been marked as private".

If you are looking to publish your package to the npm registry, then I'd recommend looking up a different guide. I have not yet published anything to the registry, so I wouldn't pretend to be the authority on it, and I don't want to go into depth with it right now since we aren't going to be utilizing it anyway.