Back to Basics: How to Set Up a React App From Scratch 2020
Building a React app from an empty directory using the latest Webpack and Babel.
Nowadays, starting a React app is as simple as typing a line of command into the terminal, taking for granted what happens under the hood. We use create-react-app or other boilerplates to start the development process and dive straight into the actual React code.
However, it would be a great learning experience (especially for those who are beginners) to set up a react app from scratch on your own. It will cement your understanding of the bits and pieces that goes into a react application from scratch to deployment. As the saying goes, you learn stuff from breaking things apart and putting it all back together.
I recommend you to follow along and code on your own while observing this ‘tutorial’. Speaking from experience, coding on your own will help cement the concepts and understanding rather than just reading along.
First and foremost, you will need a code editor where you will actually do the coding. You may use the text editor that your machine have provided, however that is really not recommended. You will not get syntax highlighting, code snippets, autocompletion, and simple error detection (just to name a few benefits) from using a plain text editor.
There are many code editors out there. I personally opt for Visual Studio Code as it is light, open sourced (great community), has a great UX, has built-in git, and has its own terminal (this last one was what made me convert from the last code editor I use)
Installing Node.js will also install npm. According to it’s official site, npm is two things: it is a repository of open-sourced packages and it is also a command-line utility for interacting with said repository. Npm can be used to install open-sourced packages, manage project versions, and manage dependencies.
Now that we have a code editor, Node.js, and npm installed in our machine, let us dive straight into the project.
First of all, you will need to create an empty directory where all the files needed for this react app resides. Inside the terminal, type:
mkdir (make directory) is a command to create a new directory while
cd (change directory) let’s you change the current working directory. From the above instructions, we have created a new directory called “react-app” and then we changed the current working directory so that we are now inside the react-app directory.
Create a package.json file by typing in the following command at the root of react-app folder:
npm init -y
Package.json file is (as the extension implies) a json file which holds an object of key-value pair). By having a package.json file we could install packages and dependencies needed for this project. Inside the package.json file, you should see something like this:
It holds the current project’s metadata (name, version, description, keywords, author, and license) and some other stuff (we will get to this later) that can be useful .
There are 3 babel dependencies we need to install:
@babel/core — This contains the babel core configuration,
@babel/preset-react — This contains different plugins to enable React syntax parsing and transformation.
npm install --save-dev @babel/core @babel/preset-env @babel/preset-react
We use the
--save-dev flag so that these babel packages are only used in the development environment. After running the commande above, in your
package.json file, you will see a new key called
devDepencies which has an object containing the information of packages (and version number) that we have installed as dependencies in the development environment. This is one of many ‘other stuff’ mentioned earlier about what information package.json can hold.
Note that after installing a package, there will be a file named
package-lock.json and a directory called
node_modules created at the root of the folder.
package-lock.json basically helps determine the exact version of dependecies installed when the project folder is replicated elsewhere using
npm install. Meanwhile, the
node_modules directory is where all the installed packages resides, so don’t be surprised if the directory size is massive. You can read more about
npm install --save-dev webpack webpack-cli webpack-dev-server
At the time of writing, the latest webpack version available is webpack 5. There are three packages that need to be installed:
webpack is the core webpack functionality package. To use
webpack-cli package also needs to be installed along. Lastly,
webpack-dev-server enables a development server that can be used in a development environment only which provides live reloading.
Of course. It is the main package that will need to be installed. However, different from the last two groups of packages (babel and webpack), react should not be installed using
--dev-save flag, instead use the
-- save flag (or no flag at all). This is so that react can be used both in the production environment and in the development environment. Install react by typing the following command at the root of the react-app directory:
npm install react react-dom
For react to work, we need to install two main packages: react and react-dom. The react package only contains the functionality to work with react components. However, to interact with and render to the DOM, we need the react-dom package.
Now that we’ve installed the necessary dependencies, let’s configure our app so that we can code with react. We need to create two directories called
src. Inside the src directory, create a file named
app.js From the root of the react-app directory, type in the following commands to the terminal:
If you’re using a windows machine, instead of
touch, you should use the
ni (new item) command. The
public directory is where our ready-to-be-served files reside. The
src directory is where we will actively code in. The first file in the
app.js, is our entry point to our react application. Our code should begin from here on out.
Next, we need to configure webpack to tell it to bundle files starting from the entry point, the
app.js file. Create a file called
Our folder structure should now look like this:
webpack.config.js file, we type in the following code (explained below):
- We require Node’s
pathmodule in order to work with file and directory paths.
- We export an object, again, using Node’s
module.exports. The exported object from
outputkeys (which will expand later on). The
entrykey specifies which module or file should webpack use to begin building out its dependency graph. From that point, webpack will determine which other modules that entry point depends on. Our entry point, as specified above, is the
outputkey, on the other hand, specifies the name of the file and the path where the created bundle should be emitted. We specified the emitted file name to be
bundle.jswhich resides in the
publicdirectory created earlier.
To test whether what we’ve configure so far works, run the
webpack command in the terminal at the root of our project folder. Chances are, an error will be thrown:
webpack : The term 'webpack' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
What happened? Because we have installed
webpack-cli locally as
devDependencies (as the documentation suggests), we need to access the webpack command from the local
node_modules directory. Run the webpack command again but this time from the
node_modules directory. At the root of the project, type the following in the terminal:
When the command is successfully executed, you should see a new file called
bundle.js inside the
public directory, as specified in the
bundle.js should still be empty as we haven’t added any code in
babel-loader by running the following command in the terminal:
npm install --save-dev babel-loader
Add babel-loader in the webpack.config.js file like so:
3. We added a new key called
module inside the
module.exports object in
babel-loader, except those inside the
babel-loader is set up in the webpack.config.js file, we need to create another file to configure babel at the root of the folder called
babel.config.json. In earlier versions of babel, this configuration file for babel was rather named
.babelrc. However, following the latest babel documentation, we use the
babel.config.json as recommended:
babel.config.json, add the following code:
babel-loader will try to find the babel configuration file —this
babel.config.json. The code in this file instructs
babel-loader to use
@babel/preset-react presets that we have installed earlier when transpiling our code.
In order for us to see our react-app site (and changes to it) on the browser in development mode, we take advantage of
webpack-dev-server. The configurations for
webpack-dev-server should also be inside
webpack.config.js add the following code inside
module.exports (instruction number 5) object:
5. The devServer key describes the configurations that can be made to webpack-dev-server. Here, we tell webpack-dev-server to serve files from our public directory.
Lastly for the configurations, we need to add the following scripts in
To make our development easier, we add three scripts to run from npm:
build command will instruct webpack to start building the dependency graph from the source file and generate the bundle into the targeted directory according to
webpack.config.js file we created earlier. Instead of repeatedly instructing webpack to run the full build manually, we can use the
watch command. This command will instruct webpack to listen to any changes saved in our project and immediately recompile to a new bundle. Meanwhile, the
start command will instruct webpack to start a simple development server so that we can see our project live in the browser. Note that in earlier versions of webpack, the instruction to start a development server would be
webpack-dev-server --watch. Any changes saved to our project will automatically reload the server with the new changes.
npm run build|start|watch
Our project needs to have an html file where our react app can render into. We create a standard html file in the public directory. From the root of our project directory, type the following in the terminal to create an html file:
Next, add the following html inside
Here is a standard html file boilerplate with a head and body tag. Inside the head, goes our meta tags which defines the html metadata. The area we need to focus is the body tag.
6. Inside the body tag, there are two tags: a
div tag with the id “root” and a
script tag that references to our bundle.js file created by webpack. The “root” div is where our react-app will render into. Meanwhile, bundle.js file is where our react-app from
Now, let’s code our react-app inside
src/app.js like so:
Inside src/app.js, we create an App component which will be rendered into the root div that we specified earlier.
To test whether our app works, let’s recompile our app.js using webpack:
npm run build
We fire up our development server by running the following command at the root of the project folder.
npm run start
The result of that command in the terminal should point to a localhost url (usually http://localhost:8080/) where the current project is being served. Entering that url in the browser will take you to the react-app page:
We did it! We have made a react-app from scratch using the latest from tools from babel and webpack. If we make any changes to our code in
src/app.js, webpack will automatically recompile and the changes should be updated live as we save the file.
I encourage you to poke around just for the sake of learning how everything in our react-app directory works. I recommend you start from
Next, we will try and build an Express server where we could serve this app from. The app could be delivered/served to the client via client-side rendering or server-side rendering. To understand how client-side rendering works using Express back end (and continuing with this react-app project from scratch), follow the link below:
Back to Basics: Client-Side Rendering a React App Using Express.js
How to serve a react app using Express.js by implementing client-side rendering solutions.
To understand how server-side rendering works using Express back end, follow the following link instead: