Yet another Beginner’s Guide to setting up a React Project — Part 2
We set up a simple React App in Part 1. We used React, React DOM and webpack-dev-server as our dependencies. We will extend the same project with other goodies that make web development easier.
Let’s begin!
JSX and React
In the last article we saw that to write <div>Hello World</div>
in React, we wrote React.createElement("div", null, "Hello World")
. If we want to render the following simple HTML on a page
We need to write this in React.
This looks scary! Not to mention that it is difficult to read, maintain, or understand what is going on in between all the null
s.
We, as programmers, can do better.
Facebook already realised this problem. Writing components or elements using “pure” React API was not going to work. So they created an easier-to-understand extension of React. They called it JavaScript Syntax eXtension (JSX for short). It resembles HTML syntax with few minor changes. However, JSXs are expressions of JavaScript, unlike HTML. By that I mean that you can do this: const hello = <h1>Hello</h1>
. It is perfectly valid code. Under the hood, they become regular React.createElement
functions. Hence, they can leverage the full power of JavaScript. You can read the full introduction here.
But now we have a problem. If you change the index.js
page to include JSX, like this — you get an error.
Notice how line 5 has been changed to JSX. If we run server again, we will not get our usual output. Instead, we will get an Unexpected Token
error.
The problem is that React still does not understand JSX. JSX is for our convenience and visual aid. So before you can start using JSX, you need something that can transform the JSX to a bunch of createElement
functions.
Navigating through the Babel Ecosystem
The transformer that we spoke about in the last paragraph is called a transpiler. A transpiler is a program that converts the source-code of one programming language to an equivalent source-code of another programming language. In this case, it is JSX to normal React/JavaScript functions. The transpiler that we are going to use is Babel.
You know the drill by now. You need to install babel using yarn. Type yarn add -D @babel/core @babel/preset-react
. We are using the latest versions of these packages. Notice that we have installed two modules: babel/core and babel/preset-react. The reasons are as follows-
Babel Core: This is heart and soul of the Babel compiler. Consider this as the engine that is going to run the transpiler. It contains the transformation logic. But the core doesn’t do anything on its own. You need to specify individual plugins for specific transformations.
Babel Plugins: The Babel core is able to carry out conversions from one language type to another. However, we still have to specify that we need to convert from JSX to normal JavaScript. For that we need to install plugins. Think of a babel plugins as a small unit of transformation. A plugin specifies
- What source code to transform
- What it should be transformed into
- How to do that transformation
Now, React JSX transformations require 6 plugins, namely:
@babel/plugin-syntax-jsx
@babel/plugin-transform-react-display-name
@babel/plugin-transform-react-jsx
@babel/plugin-transform-react-jsx-self
@babel/plugin-transform-react-jsx-source
But developers of Babel thought that we, as programmers, can do better. Since a lot of people are going to use React, why not make pre-existing sets of these plugins and call it presets.
Babel presets: The presets are a collection of plugins. So, instead of installing the 6 individual plugins for React, we just installed babel/preset-react. It will install the 6 plugins for us.
To learn more about Babel, you can try the interactive editor here and see live transpilation.
So now you also have a way of using JSX in your React Apps. If you run web server again, you will still get the same Unexpected Token
error. What happened now?
The Webpack Jungle
We have the transformer: Babel. We also have the transform-ee: JSX. What we need now is the program that initiates the transformation. We can do so by installing babel/cli and giving it the JS file to transform. But this would mean that every time we change the source code, we would need to run babel again.
We, as programmers, can do better. We can make this process automatic.
We are going to use webpack to achieve this. Webpack is a module bundler. It is capable of a lot of things which we will discuss in a moment. Remember that we already installed webpack in Part 1. Webpack has 4 core concepts to understand.
- Entry: The module(s) from where to begin bundling.
- Output: The location where to emit the bundled modules.
- Loaders: Loaders are utilities that enable webpack to do some processing per module. Loaders can transform, or pre-process modules before the modules are bundled together.
- Plugins: The plugins do not work per module. They extend the capabilities of webpack itself. For example- Let’s say you need to minify or compress the bundle. You can use webpack plugins to do these tasks.
Let’s talk about module bundling now.
Remember how we have installed 6 modules ( 2 dependencies + 4 devDependencies ) till now. They are React, React DOM, webpack, webpack-dev-server, babel/core, and babel/preset-env.
To render react components in the browser, the react
and react-dom
modules must be present while the HTML page is being evaluated. Now there are two ways to do this:
- In the first, we put three
<script />
tags. The first two contain thereact
andreact-dom
scripts. The third one will contain our components that needs to be rendered. Like this:
<script type="text/javascript" src="url/of/react.js"></script>
<script type="text/javascript" src="url/of/react-dom.js"></script>
<script type="text/javascript" src="url/of/our/components.js"></script>
But this method is not used.
- In the other method, we can bundle
react
,react-dom
and our components into a single file. We can name the resulting file asbundle.js
and just add that one file into the script tag of our HTML page. We did this in part 1. Look at line 9 ofindex.html
. We addedbundle.js
insrc
ofscript
tag. Thisbundle.js
was provided by webpack-dev-server after it did the bundling using webpack.
You may be thinking that adding 3 scripts is not that big of a deal. But imagine if your application has 20 modules or 50 modules. Also, what if those modules depend on each other. You will always need to put your script
tags in such an order that the dependent is always after the thing that it is depending on. It is also called topological sorting. Doing this by hand can be very consuming and error prone.
Configuration, configurations, everywhere!
Before you can go around bundling modules, webpack needs a configuration file telling it where to begin(entry module) bundling, and where to put the output.
By default, the configuration file for webpack is called webpack.config.js
. It contains an object that lists various configurations. For our purposes, we need this configuration.
A few things to note in the config
object are:
- The
entry
is an array that lists the modules from where to begin the bundling. It isindex.js
of Part 1 in our case. - The
module
key lists configuration regarding modules. It has a sub-keyrules
that accepts an array of rules applicable to each module. - The
rules
array comprises objects that has a few keys such astest
,loaders
,exclude
and many more. - The
test
key is a regular expression(regex) that checks whether a module is a JS module. - The
loaders
will apply each loader in the array on the modules that passed thetest
. - In this case it is
babel-loader
. It will transform JSX to normal functions. - The
exclude
fields will exclude certain matching paths since they may not be part of our application such asnode_modules
.
In short, webpack checks each file and if the file extension is .js
, webpack runs babel-loader
on it, and then includes it in the bundle.
So create a webpack.config.js
and paste the above configuration in it. But before you run the project, you need to install babel-loader. Type yarn add -D babel-loader@8.0.0-beta.0
. We are adding an @
after babel-loader because we want a particular version of it. In this case, it is 8.0.0-beta.0.
But the struggle is not over just yet. If you type yarn start
hoping to see some result on the webpage, you’ll get an error. Again. Now, what more is missing?
Let’s get things straight once again — We have a transformer: Babel. We have the transform-ee: JSX. We have an initiator and a bundler: webpack. We have configurations of webpack. What we need now are configurations of Babel. Yes! Babel also needs configurations. In Babel, we have the core
and react-presets
. However, we need to inform the core that we have react-presets and it needs to do transformations using these presets. Hence, a Babel configuration file.
Now, there are many ways to specify Babel configurations. One of the ways is to create a file called .babelrc
. The rc
is related to run command. This convention is a reminiscent of Unix style nomenclature. You can read more here.
In the .babelrc
file, paste the following:
It contains one object that specifies that Babel needs to use react-presets for transformations.
Your folder contents should look like the folder structure in the image.
In index.js
, replace line 5 with <h1>Hello World with JSX, Babel, and Webpack</h1>
.
The final index.js
should now look like
Now, we can execute yarn start
and if everything is set up correctly, you should see “Hello World with JSX, Babel and Webapck” when you navigate to http://localhost:8080/.
Originally published at codeburst.io on February 8, 2018 by Arfat Salman