Babel Tutorial Part 2 - React and JSX
Greetings, friends! I hope you learned a lot in Part 1 of my Babel series. Today, I'd like to actually setup a React application using Babel but without Webpack. If you have ever used Create React App, then you should know that it uses Babel and Webpack internally.
First, I'll make an assumption that you have Node and npm installed on your computer already. If not, then please go to Node's homepage to install Node, which will then prompt you to install npm. Once these are installed, create a directory called babel-tutorial-react and navigate to it:
mkdir babel-tutorial-react && cd $_
Then, you can run the following shortcut command to quickly bootstrap a new project with a package.json file:
npm init -y
We need to install three Babel packages as dev dependencies: @babel/core, @babel/cli, and @babel/preset-react. We need @babel/core to orchestrate between the @babel/parser, plugins, @babel/generator. Using @babel/cli lets us use a CLI to transpile our code. We will use @babel/preset-react, which contains all the plugins we need to understand JSX and compile it down to React createElement
methods.
npm i -D @babel/core @babel/cli @babel/preset-react
Next, let's add the serve npm package to serve our assets from a small server.
npm i -D serve
We will change our package.json file, so that we have a script named "start" that simply runs the command, "serve". Your package.json file should look like the following so far:
{
"name": "babel-tutorial-react",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "serve"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/cli": "^7.10.5",
"@babel/core": "^7.11.1",
"@babel/preset-react": "^7.10.4",
"serve": "^11.3.2"
}
}
The next thing we want to do is to create a new html file named index.html
that uses React from a CDN.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Babel + React Demo</title>
</head>
<body>
<h1>Babel + React Demo</h1>
<div id="root"></div>
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<script src="src/index.js"></script>
</body>
</html>
The <div id="root"></div>
element will be replaced by our React code. As you may know, we need at least one root element to bootstrap our React application. I have also added a small script tag that loads a JavaScript file from src/index.js
. Let's create a directory named src
and a file inside it named index.js
.
function Celebrate() {
return <p>It's working! 🎉🎉🎉</p>
}
ReactDOM.render(
<Celebrate />,
document.getElementById('root'),
)
Alright, we added our React code! Let's see if it works! We'll start our server using npm run start
(or using the alias, npm start
). This will start a server on an unused port and serve up our files as static assets. Is our JSX working?
Nope, of course not! We didn't set up Babel yet! Is the console complaining? Yep, as expected. We need Babel to parse JSX and transpile it, so we can run proper JavaScript in the browser.
It's always a good practice to setup a project using a Babel configuration file. It's recommended to name this file babel.config.json
if you don't plan on changing your Babel config dynamically. If you do plan on changing this file or running a dynamic Babel config that may change upon every build of your project, then you should use a babel.config.js
file instead, so you can control the Babel config through JavaScript. However, it's best to use babel.config.json
, so that bundlers such as Webpack can cache the results of Babel safely.
We will create a babel.config.json
file that uses the @babel/preset-react group of plugins:
{
"presets": ["@babel/preset-react"]
}
Since using this preset is so common, Babel provides a shorter notation:
{
"presets": ["@babel/react"]
}
Native JavaScript doesn't understand JSX syntax. Babel to the rescue! Let's add a script to our package.json file called build:
"build": "babel src --out-dir lib"
Alternatively, you can use a shorter syntax:
"build": "babel src -d lib"
This command will use @babel/cli to compile all files in the src
directory using all the presets and plugins found in our Babel config file, babel.config.json
, and output new files into a directory called lib
.
Our finished package.json file should look like the following:
{
"name": "babel-tutorial-react",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "serve",
"build": "babel src --out-dir lib"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/cli": "^7.10.5",
"@babel/core": "^7.11.1",
"@babel/preset-react": "^7.10.4",
"serve": "^11.3.2"
}
}
If you run npm run build
, then you should see a lib
directory be created with the transformed index.js
file. If you look inside of it, then you can see that Babel has transpiled the JSX down to React methods:
function Celebrate() {
return /* #__PURE__ */React.createElement('p', null, 'It\'s working! \uD83C\uDF89\uD83C\uDF89\uD83C\uDF89')
}
ReactDOM.render(/* #__PURE__ */React.createElement(Celebrate, null), document.getElementById('root'))
Don't worry about the /*#__PURE__*/
annotations. These are used with Webpack to help with tree-shaking. Babel also converted our three 🎉 emojis into three pairs of Unicode code units.
Now that we have our transpiled JavaScript, let's change our index.html
file to import code from lib/index.js
instead of src/index.js
:
<script src="lib/index.js"></script>
If your server is still running from using the npm run start
command, then all you have to do is refresh the page to see the result of your updated index.html
file. If not, then you'll need to make sure to start the server again. With your transpiled code running, you should see your React code running successfully.
Yes! 🎉 It's working! You have successfully used Babel to transpile JSX without using Create React App or Webpack. Babel plugins are awesome! It's important to keep in mind that the Babel parser already understands JSX. If you were to invent your own kind of syntax, the parser would have to be able to understand it. If for whatever reason, you want to modify the parser, you would need to fork @babel/parser and add a plugin to consume your custom parser.
createElement
functions too!If you want to download the finished code, you can check out my GitHub repository, or you can clone the repo using:
git clone https://github.com/inspirnathan/babel-tutorial-react.git
Phew! Still with me? In Part 3, we will discuss how to add source maps to the project, so we can debug code by looking at the original source code instead of the transpiled code. Happy coding!