If you haven't been living under a rock for the past few years, you'll likely know that React is one of the dominant front-end frameworks of the current era. As of when this article was written (late 2020), React was the second most popular front end framework behind jQuery and gaining steam. Written by a team at Facebook, it's a pretty cool new approach to web frameworks in the quickly accelerating rate of web development. It's built on a virtual DOM and makes changes based on DOM diffing , so it's really fast on switching views.
React's design philosophy is based on the idea that everything is a component, which is simply a reusable bit of code that can create a displayable element or control the app in some way (or both). A React app is made by combining and nesting components, which can be made up of more components or React's base elements which roughly mirror the displayable HTML elements.
Components are normally written in JSX (short for Javascript XML), which is a non-standard extension of Javascript syntax invented by developers at Facebook as an easier way to write React. This syntax is the same as XML syntax in that it has a tag name, attributes, and children, and essentially serves as syntactic sugar for React's createElement
method, which also takes a tag name, properties, and children as arguments
JSX is definitely cleaner and a lot more elegant to write in, but since this syntax is not standard to Javascript, it needs to be preprocessed and turned into standard calls to the React library that can be understood by a Javascript runtime.
In order to set up a project where we can use JSX for React, we'll use three popular Javascript libraries: React, Babel, and Webpack. There's a number of script out there that will create a React project for you, like create-react-app
which offers options for all kinds of extras and advanced configurations, but if you're like me, you want to figure out how to do it yourself. So let's get into it!
In this instructional, we're going to stack some JS libraries together. Our base will be Webpack, which is a Javascript module bundler. Essentially, Webpack begins with an entry file, which it traverses, following each function call and import
and require
to build an internal dependency graph, which maps all the requisite code that the entry file needs to run. Then it processes only the needed code and bundles it together in a single Javascript file which can be sent to a client to run on a website or application.
A key feature of Webpack is its loaders, which essentially can be set to preprocess imported files before being bundled. We're going to use a loader which runs through a powerful Javascript transpiler called Babel in order to translate our code. Babel can be set to transpile a number of different syntaxes to a standardized target syntax (e.g. ES5, which is supported by the vast majority of browsers in use today). It can convert Javascript-based languages like Typescript, Clojurescript, or Coffeescript, as well as translate extended syntaxes like JSX to different target libraries like React, Inferno, Preact, or even your own.
So you might wonder, why use Webpack at all if Babel is the one converting JSX to React? Can't we just use Babel by itself? And the answer is yes, you can. Babel has a CLI package which allows us to process files on a one-off basis. But this approach suffers from a lack of scalability — for any project that uses more than a few files, using the CLI becomes a non-trivial task. Not to mention that in a web app development context, the code we send to the user should be bundled and optimized to minimize its size, as well as be compatible with the most browsers possible. Using Babel as a loader in a bundling tool like Webpack provides us with the intrinsic benefits that such a tool provides, as well as the ability to easily add new types of web development tools and languages, so it's an all-around much better strategic approach for most projects.
These instructions assume you have Node and npm installed on your machine. You can check by typing node --version
and npm --version
respectively at the command line, and you should get something like v12.10.1
and 6.0.0
. If you get an error for either command, you need to install the program you're missing.
The first thing is to make two folders in the root directory: src/
and dist/
. In the project, we'll place all the source code in the src
directory, and Webpack will place the built code in the dist
folder.
So go on ahead and start a new npm project if you haven't already, and install Webpack at the command line:
shell
Wait, what's --save-dev
? --save-dev
saves the installed package as a development dependency, meaning that it isn't required to run the project, but it is necessary for development. In this case, once Webpack has build the project (generated a bundle), we don't need it to run the project, but if we're developing, we'll very likely need to have Webpack to rebuild the project.
The webpack
package provides the core functionality, while webpack-cli
provides an interface which can be accessed through npx, npm's package executor.
Webpack can be run as is, but to tune it to our needs, we should give it some configurations. So make a new file in the root directory called webpack.config.js
, which is the default config file that Webpack looks for.
webpack.config.js
Here, we tell Webpack to enter at the file src/entry.js
and to put the output bundle in dist/
and call it bundle.js
.
That's all we really have to do to set up Webpack for right now. But another important thing we need to do at this point is to add an HTML file to send to the client. React is a single page application (SPA), which means that instead of sending a user new HTML every time they navigate to a new page, the change in display is controlled by Javascript. So in practice, when a client navigates to the webpage, the server sends a single HTML file with no rendered content and the Javascript needed to build and change the webpage view attached as a script. Webpack creates the Javascript bundle for us already, but we need an HTML file to send to the user which references it. It will be pretty simple: we just need an empty div element with a unique id to render our app into (if you've ever built a webpage with jQuery or ES6, you might recognize this way of doing things), and a script tag to reference the bundle.
dist/index.html
So now we can serve that HTML file to clients, and the bundled code will be sent along with it.
Next, install Babel and some presets we'll need to make it work:
shell
@babel/core
provides the core functionality that Babel needs to run, babel-loader
provides it in a Webpack loader, and @babel/preset-env
and @babel/preset-react
are transformation presets (env
converts ES6 to ES5, and react
transforms JSX into vanilla JS syntax).
Babel looks for a file called .babelrc
to get its configuration options. We'll keep this file really simple since we just need to tell Babel to use the transformations we installed.
.babelrc
Now we can use the Babel loader in Webpack. The way this is done is via defining rules, which essentially tell Webpack which loader(s) to run a file through based on regex matching with its filename. We can easily filter by filetype with $
to match the end of the string.
webpack.config.js
Now we've told Webpack that for every file ending with .js
or .jsx
(excluding those in node_modules
), it should preprocess it with Babel before bundling.
Now we can use ES6 and JSX freely and Babel will convert them to compatible syntax. But in order for the transpiled code to work, we need to add the missing piece to our project:
shell
react
is the React core library, and as the name might suggest, react-dom
provides a bridge between React and the DOM, which we need to inject our React app into the DOM in order to display it.
Aaaaannnd that's it! React doesn't require any configuration out of the box. Since we've laid all the necessary groundwork, we can simply start writing code. Let's make a super simple web app:
src/entry.js
src/greeting.js
And if we run npx webpack
, it'll do its thing and you'll see a bundle.js
file pop up in dist/
. If you open or serve the HTML file in a browser using your preferred method, you should see your app there in the screen!
One thing you'll have to keep in mind is that to render your app into the DOM, you need to add the ReactDOM.render
call in a function attached to your document's onload
event, or some variant thereof. This ensures that the <div>
element is actually in the DOM before we go trying to put stuff in it.
So you've got React up and running with JSX. Great! Now what? Well obviously you can start building that sick web app you've always wanted to. There are a bunch of different packages of React components which provide different functionality. For example, if you want to add different pages to your web app, you can check out react-router which is the de facto routing library for React. Other cool libraries include Material UI, VISX, Mapbox GL, and more. Also, this project only scratches the surface of Webpack's functionality. You can add all sorts of cool things to enhance the development and deployment of your project like CSS modules, Typescript, SASS/SCSS, inline images, an auto-refreshing dev server and more. Furthermore, you can explore Babel's plugin ecosystem and check out things that might be useful to you. This stack provides a great toolset to build a clean and fun project, so get out there and do something cool!