React has become the leading frontend library of choice among developers in recent years. The best way to learn and practice any programming language tool is to build stuff with it --- in order to do so we need to set up a coding playground. The fastest way to get started with such a project is to bootstrap it with create-react-app (CRA)
.
The reason why such a thing exists is that modern Javascript tooling has become an incredibly vast space (hilariously explained here ). Starter kits such as CRA helps us avoid navigating that landscape and focus on coding the fun stuff. However, it is still essential for developers to know what are some of the key pieces of configuring a project. We will learn just that in this step-by-step guide for a minimal React project setup.
We will learn the following in this tutorial:
- basic concepts of Webpack and leverage that to set up our project
- what is Babel, what does it do and why do we need it
- how to integrate React into our project
- how to enable hot module to reload
Let's get started by learning the basics of the tools we will use today to configure our first project.
React JS
React is a javascript library that has brought about a paradigm shift when it comes to building user interfaces. Developed and maintained by Facebook, it views the world through the lens of small, reusable components. Imagine a Lego set, where we put together blocks to create a structure. Similarly, React components don't mean a whole lot on their own, but when assembled in a systematic way through the hands of an experienced developer, it can become a powerful tool to build beautiful and complex user experiences.
Key Features
- Simple, reusable components
- Declarative. Code is more readable and easier to debug.
- One-way data binding. Data strictly flow from parent component to children component(s)
- Virtual DOM. Algorithms calculate the "diff" between current and updated DOM (through user interaction, data received from API calls, etc) to only re-render portions of the view that needs to be updated.
- Performance
Webpack
The official site for Webpack describes itself to be a static module bundler --- but I believe it is selling itself short. Yes, it is that in the simplest sense, but it can do so much more. Webpack is an incredibly configurable tool that packages all the front-end code (js, css, templating engines, static assets) and creates bundles that the browser can download to give your application functionality.
Key Features
- Module bundler. Packages front-end code into bundles for the browser to download.
- Code splitting. The bundles can be broken down further based on the page, functionality, etc so that the browser downloads as little code as possible to run the application.
- Tree shaking. If configured to do so, it will not package dead/unreachable code in the bundle.
- Loaders and plugins. Allows us to extend on the out of the box functionality provided by Webpack.
- Hot Module Replacement (HMR). During development, Webpack can swap out JS or CSS modules on the fly to update the UI without refreshing the page.
- Environment-specific configurations. For instance, we don't want to minify code in the development environment but we absolutely want to do so in production.
Babel
Babel is a javascript transpiler --- it compiles modern JS code into older versions so that older browsers can execute them. The latest versions of most browsers can parse through newer JS features, but legacy browsers can't. We don't want our application to fail to run on those browsers, and that is where Babel saves the day.
Key Features
- Compiles modern JS code into older versions of JS that older browsers can execute.
- Allows plugin presets to extend on top of its out-of-the-box functionality.
Alright, now that we've learned the core concepts of the tools we're about to use, let's write some code!
Please note: It's worth mentioning here that the node version in your machine must be 10.15.3 or higher. Check by typing node -v
in your terminal. If you need an update or don't have node installed at all, you can get the installer here
Step 1:
Open up your terminal and navigate to a directory where you would like to create your repository.
cd ~/Desktop/projects
mkdir minimal-react-webpack-babel && cd $_
mkdir -p src
This will create a directory named "minimal-react-webpack-babel" where our code will live and a "src" subdirectory inside it.
Step 2:
We need to initialize package.json at this point
npm init -y
This will create the file in one go, with most fields being empty (like description and author) and set others to default (like version set to 1.0.0). You can come back later to fill them out appropriately.
The package.json should look like this now
{
"name": "minimal-react-webpack-babel",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
Step 3:
Let's install webpack and webpack-cli in our project.
npm install webpack webpack-cli --save-dev
Pre v4.0.0 of Webpack used to look for a configuration file to run, but since version 4.0.0, Webpack is able to bundle packages out of the box.
In a later tutorial, I plan to demonstrate a more advanced setup for Webpack (environment-specific configs, linters, test runners, etc) that will build on top of what we're learning today. We will leave it in its bare-bones state for now.
Step 4:
Time to install react and react-dom.
npm install react react-dom
React should be installed as a regular dependency and not as devDependencies
because we need react available at application runtime and packaged into the production bundle of the application.
Alright, that was quick and easy! Let's move on.
Step 5:
We have to install Babel here, along with other necessary presets.
npm install @babel/core babel-loader @babel/preset-env @babel/preset-react --save-dev
Explanation: React is written using modern ES6 features that older browsers cannot execute. Therefore, we need to somehow convert the modern syntax into ES5. Webpack cannot perform this action --- this is where Babel steps in to bridge the gap. This process is called transpiling.
We installed three dependencies using the command above:
babel/core babel-loader
: the interface between babel and webpack. It allows them to work with each other to produce the final bundle.babel/preset-env
: a preset responsible for transpiling ES6 (or above) to ES5.babel/preset-react
: a present responsible for compiling JSX to regular JS. It is possible to forego installing this dependency, but then we will not be able to write our React components using JSX.
Great, now that we understand that, let's configure babel to use the presets we just installed. First, we will need to create a file called .babelrc
at the root of the project --- this will contain the config rules.
touch .babelrc
This is going to be a hidden file. Open up the file using:
open -e .babelrc
... and add the following lines and hit save:
{
"presets": ["@babel/preset-env", "@babel/preset-react"]
}
Step 6:
Let's install a dev-server now. Technically, it is possible to move forward without the dev-server, but that would mean we will have to build our project every time we make code changes to it. That is not the world we want to live in --- we want our application to update as soon as we save our code changes. This process is called Hot Module Replacement. In addition to installing the dev-server, a slight tweak to the webpack config will enable this feature for us.
npm install webpack-dev-server --save-dev
Now, in order to have webpack build our code, we will need to add a script inside the scripts
property of package.json. This will compile our code in production
mode.
We will also add a start script that will spin up our dev server and enable a seamless development environment.
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack --mode production",
"start": "webpack-dev-server --open --mode development"
},
Step 7:
The last dependencies we need to install in our project are html-webpack-plugin
and html-loader
.
npm install html-webpack-plugin html-loader --save-dev
- html-webpack-plugin will generate the HTML from the React components we're about to write.
- html-loader exports the HTML as string and can minimize it if we ask it to.
Step 8:
We're done with installing dependencies!! What we need to do now is create an HTML file where React will mount our application. Let's call it index.html
and put it inside the src
directory we created earlier.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Minimal React + Webpack 4 + Babel 7 project setup</title>
</head>
<body>
<div id="app-container"></div>
</body>
</html>
Step 9:
At this point in time, we will add minimal config rules to webpack. We will do so by creating a file called webpack.config.js
and put all our rules there. In a future tutorial, we will build on top of what we are learning today and create separate config files for development and production environments. This will allow us to segregate environment-specific rules, promoting scalability and maintainability.
Let's create that file at the project root
touch webpack.config.js
... and add the following lines to it:
const HtmlWebPackPlugin = require("html-webpack-plugin");
module.exports = {
devServer: {
contentBase: './dist',
hot: true
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
{
test: /\.html$/,
use: [
{
loader: "html-loader"
}
]
}
]
},
plugins: [
new HtmlWebPackPlugin({
template: "./src/index.html",
filename: "./index.html"
})
]
};
Explanation: These lines are telling webpack to do the following:
- devServer contains config rules for the server instance we will run to host our application using dev-server.
hot: true
enables hot module replacement. - pipe all files with an extension of
.js
or.jsx
through babel-loader, with the exception of files insidenode_modules
directory. - use the html plugin and loader we installed in the previous step to generate HTML from React components and the front end packaged code bundle and inject the bundle in a
<script/>
tag in the HTML.
Step 10:
We've reached the end of our setup process -- we're now ready to write some React !!
Let's create a components directory inside src
, and write a simple App.js
component that prints "Hello World".
import React from 'react';
import ReactDOM from 'react-dom';
const App = () => {
return (
<div>Hello World</div>
)
};
export default App;
We also need to create index.js
inside src
directory --- and import the component we just wrote.
import React from 'react';
import ReactDOM from "react-dom";
import App from './components/App.js';
const $container = document.getElementById("app-container");
$container ? ReactDOM.render(<App />, $container) : false;
The process is complete --- we've a React project using babel and webpack all on our own!! Now, if we run npm run start
, webpack will spin up the dev server and open up our application in a browser window. Additionally, since we've enabled hot module replacement, if we make code changes to our application (edit existing "hello world" component, add new components, etc), we will immediately see our application update in the browser!
The finished repo is here
Conclusion
There is little doubt that create-react-app
is the quickest and most convenient way to set up a react project (at the moment). However, it is an incredibly valuable skill to know how modern javascript tooling works --- and how we can piece these tools together to set up a front-end project from scratch.
I hope this step-by-step guide has helped you understand some of that. Thank you for reading and stay tuned for more !!