There are many tutorials out there that will get you up and running with ReactJS. Some are more detailed than others, but most never break down the configuration. As long as you copy the config files according to the tutorials, things work for you. But you don't know why. As I try to understand this myself, I thought I'd document my process here in hopes that another might benefit from what I've learned.
Source available on Github
Creating the basic project
First create a directory and name if for your project. I'm going to create one named demo
using my terminal:
mkdir demo
Navigate into your new directory:
cd demo
Next I'll open VSCode to begin creating the required files and directories. I will use the built-in terminal in VSCode, but most often, I'll use Windows Terminal at work or iTerm2 on my MacBook for other projects. Launch VSCode from within your new directory:
code .
Open the the built-in terminal from the keyboard using CTRL + `
We're going to need some basic directories for ReactJS, so let's create those next. In the root of your project, create the src
and public
folders. Inside of public
, create index.html
which will open in your editor. Type html:5
and you'll see that this is a template for some boilerplate HTML. This is a Emmet Template. Hit tab
to accept the template. Add <div id="root"></div>
inside of the <body>
tag. Your file should look similar to this:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
To wrap up our base setup, we'll initialize npm and git, and install ReactJS.
Initialize npm:
npm init -y
This will create a default package.json
file accepting defaults. It should look similar to this:
{
"name": "demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
Now let's take care of git:
git init
Then create a .gitignore
file. You can craft this to deal with your project however you'd like as you build things out. For now, my primary concern is to ignore all node modules. Add node_modules
to line 1 of your ignore file and save it. There is much to add later to this ignore file, but we won't be exploring this here.
Install React
This is a manual setup, so we're obviously not using CRA. While this is a great solution, we want more control over what gets installed and how things are configured. Let's install ReactJS. From the console, run the following:
npm i react react-dom
We have our basic packages, but later will need a router and likely other packages depending upon what you desire for your project.
Our app already has the public HTML file we need for ReactJS, but we still need to add at minimum two files to run. In the src
directory, create a file named index.js
and another named App.js
.
I recommend installing the ES7 React/Redux/GraphQL/React-Native snippets extension for VSCode.
Open App.js
and type rfce
which is snippet for a React Functional Export Component. It will automatically name your component based on the filename. If you would prefer to type the code for yourself, here's what you'll need:
import React from 'react'
function App() {
return (
<div>
</div>
)
}
export default App
Now open your index.js
file and input the following code:
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
ReactDOM.render(<App />, document.querySelector('#root'))
This code imports the React libraries we need to make our project a ReactJS application. We also import our newly created App component, and using the ReactDOM
, render it inside of the <div id='root'></div>
of our HTML file.
Getting Dev Environment Setup
We have some base files ready to go, but we have no way of building/running the project at the moment. There's a lot to handle beyond even that. Modern web development requires that we handle things like minification, transpilation, chunking and other optimizations. It's not simply a matter of HTML/CSS/JS in a static sense without regard for the user experience. We don't spend their resources as if they're limitless. We must deliver optimized applications that respect our users. We can accomplish this by configuring our dev environment with the right tooling. As developers, we take the hit in terms of tools rather than dumping unoptimized files on our users. I could go on, but suffice it to say that all of this informs our configuration in devopment.
I will be using Webpack at the core of my dev environment. Then I will be plugging in more tools that ultimately work together to provide for what I think is a decent starter environment for ReactJS.
Webpack & Babel
There are shortcut commands to use in the Node console so feel free to use those if you wish. The commands shown here may seem overly verbose, but it's how I operate.
Install Webpack:
npm install --save-dev webpack webpack-cli webpack-dev-server
Next install the HtmlWebpackPlugin
which is used to create the output HTML files that we'll be serving:
npm install --save-dev html-webpack-plugin
Before we configure Webpack, we need to install a JavaScript compiler. We'll use Babel. This allows us to write modern JS while outputting compatible code for browsers that don't support the later versions of JavaScript. Keep in mind we're working with ReactJS and Webpack, so we need to install some supporting packages to accommodate our configuration.
npm install --save-dev @babel/core @babel/preset-react babel-loader
Now that these are installed, have a look at your package.json
file's contents. If you've installed your packages in the proper locations (dependencies vs devDependencies), your file should look similar to the following:
{
"name": "demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"react": "^17.0.2",
"react-dom": "^17.0.2"
},
"devDependencies": {
"@babel/core": "^7.16.0",
"@babel/preset-react": "^7.16.0",
"babel-loader": "^8.2.3",
"html-webpack-plugin": "^5.5.0",
"webpack": "^5.64.1",
"webpack-cli": "^4.9.1",
"webpack-dev-server": "^4.5.0"
}
}
You can see we've setup React to run as a standard dependancy while the rest are installed as developer dependancies. Our dev environment should usually be heavier than what we serve up, so this looks good.
We're almost there, but still need to configure everything we've just installed to work together and serve up our app in our development environment.
Configuration
That last thing we need to do is configure our base ReactJS app. There are two files we'll need to create: a Babel configuration file and a Webpack configuration file.
Create .babelrc
in the root of your project. Note the .
in front of the filename. We need to add a line to this new file that enables a preset for ReactJS. Essentially, today's browsers do not understand JSX, so this preset allows Babel to convert our code for use by our users. Add the following to your .babelrc
file:
{
"presets": ["@babel/preset-react"]
}
That's all we need for the preset configuration. Next we will be working through Webpack's configuration, which requires some explanation.
Let's create our webpack config file. Create a new file in the root of your project named webpack.cofnig.js
.
Check out CreateApp.dev to explore different configurations.
Here's my config file. Feel free to copy/paste this into your new file.
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
devServer: {
historyApiFallback: true,
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
chunkFilename: '[id].js',
},
resolve: {
extensions: ['*', '.js', '.jsx', '.css'],
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
include: path.resolve(__dirname, 'src'),
exclude: /(node_modules|bower_components|build)/,
use: ['babel-loader'],
}
],
},
plugins: [
new HtmlWebpackPlugin({
template: __dirname + '/public/index.html',
filename: 'index.html',
inject: 'body',
}),
],
};
So what's in this file? Let's start from the top and break it down in simple terms.
entry
configures our root app file, which in our case is located at './src/index.js'
.
devServer
set to true
when relying on HTML5 History API
output
path - sets up where our generated files are output. You'll see
__dirname
, which is a Node.js variable that represents the path of the current module.filename - the file that will be output
resolve
- extensions - an array of file extensions for your project. Webpack maps these extensions to module paths until it finds a match.
module
rules (loaders in older versions)
test - this regex value is how we tell our rule which file types should go through the loader we're using
include - the path to the source files
exclude - pipe-delimited list of paths the loader should ignore
use - the loader we're using, in our case Babel
plugins tells Webpack which plugins we want to use
new
HtmlWebpackPlugin
- the name of the plugintemplate - the location of our app's template
filename - the file to write the HTML to
inject - injects all assets into the given template. Options are
true
,head
,body
orfalse
.
Finally, we need to edit our package.json
file to enable our local dev server to run in node. In the scripts section, add a comma ,
to the end of the line "test": "echo \"Error: no test specified\" && exit 1"
and on the next line input the following:
"start": "webpack-dev-server --open --hot --mode development"
Save your package.json
file.
Run Your App
We should now have a base manually-configured ReactJS application. To give it a spin, run the following command:
npm run start
You should see a blank page served to your browser from localhost. This doesn't really prove that all is well. Let's add a h1
to our App
component and watch the page update upon save. Here's my App.js
file after adding the header:
import React from 'react'
function App() {
return (
<div>
<h1>Demo</h1>
</div>
)
}
export default App
This should have loaded your page with the new header automatically thanks to Webpack's hot reload.
That's it for now. This should get you going on a super basic project. If you're new ReactJS, take this opportunity to get familiar with everything here before moving on.
This is Part 1 in the seriesConfigure a Base ReactJS App Manually. Parts 2 through 4 are coming soon and will be as follows:
Configure a Base ReactJS App Manually - Part 2: Linting and Formatting
Configure a Base ReactJS App Manually - Part 3: CSS in JS using Styled Components
Configure a Base ReactJS App Manually - Part 4: Implement a Design System
Originally intended as a series. Now cancelled.