04/25/2016

Bowst about React: Part 2

Apps, Front-End Frameworks, ReactJS, JavaScript

Bowst About React

Welcome back to Bowst about React!  If you missed our last segment, which introduced the series and provided an overview of ReactJS, we highly recommend checking it out here before continuing. In this post, we’ll be discussing best practices/libraries for configuring a front-end build system to support precise and rapid development for your React project. We’ll also look at a simple “Hello World” React component. To see complete code examples of the concepts discussed in this post, checkout Steps 1 and 2 of the Bowst about React Github repo.

Wait a Minute…

At this point, you’re probably wondering why we’re talking about “building” JavaScript.  Isn’t it an interpreted language that doesn’t need to be compiled? Why yes, my good developer, you are absolutely correct.  But building React components using only pure JavaScript is non-intuitive, extremely verbose, and very difficult to maintain, so Facebook developed a syntax extension to JavaScript called JSX which makes authoring React much more comfortable for front-end developers. There are countless upsides to this technique, but there is also one downside: JSX files cannot be natively interpreted by the browser. If you’ve ever worked with SASS or LESS, you should be familiar with the concept. We need to create a system for compiling our JSX files down to native JavaScript that the browser can parse and execute.

The most basic way to do this would be to simply compile each individual file to JS and include them on the page via script tags. However, since React encourages breaking out code into separate files to encapsulate component and functionality, you’d soon be faced with adding script tags for hundreds of files…  and you would go crazy. No one wants that, so instead, let’s look into ways to bundle all of our files together.

Here’s where we’re at — our build system needs to accomplish two main goals:

  1. Compile our JSX files into plain old JavaScript
  2. Bundle all of that JS together

Let’s tackle these one at a time.

Compiling JavaScript

In order to compile our JSX files into JS files, we here at Bōwst like to use Babel. While there are a few other libraries out there for accomplishing this, Babel has emerged as the de-facto standard; it is a modular JavaScript compiler which can easily be extended with “presets” to compile specific syntactic extensions, including JSX using the babel-preset-react package.

But that’s not all! Babel also includes presets for ES6 syntax, which is the next generation of JavaScript and will (eventually) be interpreted natively by the browser. For now though, you can use Babel to write code using awesome features such as arrow functions and spread operators, and let Babel compile it down to something that can be understood by current browsers.

In order to install this, you’ll need nodejs and the node package manager (npm).

Got them installed?  Good.  Here’s the command you’ll need:

npm install --save babel-core babel-preset-react babel-preset-es2015 babel-preset-stage-0

I know what you’re thinking: Wow, that’s a lot of packages! However, all we’re really doing is pulling in babel-core and a few presets we’ll need to handle our ES6 and JSX syntax.

Bundling Files

Now we’ve got a tool for compiling our JSX files.  Excellent. We could simply use Babel from the command line and painstakingly run it for each of our files, but we already decided that was insane. Instead, we’re going to use a bundler called webpack. When using webpack, each file you want to generate has a single entry point, which uses node style `require` statements to import the dependencies each file needs to execute properly. By recursively iterating over these require statements, webpack can gather all of the code you’ll need to run your application and bundle it together into a single file.

Here’s the command to install webpack:

npm install --save webpack

Webpack has the concept of “loaders” which let you introduce middleware to optionally transform your files in someway. Guess what we’re going to use as a loader for our JSX files? If you guessed Babel, you’re right! Check out the command below to grab the babel loader:

npm install --save babel-loader

Almost there! All we need now to is to write a configuration file for webpack to help it understand where your project’s entry point is,and which loaders to use for which file types. Checkout the sample `webpack.config.js` below — we’ll catch up when you come back.

//bring in the node path utility
var path = require("path");
//export our configuration
module.exports = {
	//entry determines the entry point for our app
	entry: {
		//keys in the entry object are the bundle name, and the value is the relative path to entry point
		app: "./src/mount.jsx"
	},
	output: {
		path: path.join(__dirname, "dist"),//define the path where our files will be generated
		filename: "[name].bundle.js"//name of the file, [name] will be replaced with key in entry object ('app')
	},
	module: {
		//tells webpack which loaders to use
		loaders: [
			{	//regex expression with will be tested against the filename  
				test: /\.jsx$/,
				//define the loaders to use for files that meet the test defined above
				//use babel and include the es2015, react, and stage-0 presets
				loaders: ['babel?'+JSON.stringify({presets:['es2015', 'react', 'stage-0']})], 
				//make sure to exclude anything in the node_modules folder
				exclude: /(node_modules)/,
				//tell babel loader to cache the results of the loader for faster builds
				cacheDirectory: true
		    }
		]	}
};

Pretty straightforward, right? In this simple example, we are just telling webpack to start with the `src/mount.jsx` file (discussed below) and pull in dependencies from there. We also politely inform webpack that when it encounters a file with a .jsx extension, it should pass it through the babel compiler before including it in the bundle. After loading and bundling all the files together, we tell webpack to write the bundle to the `dist` directory with an extension .bundle.js (see the output property above).

Hello World!

Now that we’ve got a totally awesome build system in place, let’s start building our app! First, we’re going to create an App component at `src/app/app.jsx`.To begin, we’re going to need a dependency to the React library itself. Let’s do that right now:

npm install --save react

Got it? Righteous. Check out our “Hello World” app JSX file below:

//this is ES6 syntax, it's essentially equivalent to: var React = require('react')
import React from 'react';

//This is also ES6 syntax, it's similar to module.exports = React.createClass({});
//whatever is `exported` from this file will be available for other files to import (like we did with react above)
export default class App extends React.Component{
	render(){
		return <h1>Hello World!</h1>
    }
}

Awwww, our first React component!  It’s so cute! Components that output markup do so by returning it in the `render` function. This is the fundamental awesomeness of JSX — we can define the markup that our component should emit using an XML syntax that is fairly close to HTML (though you should note that there are some key differences).

mount.jsx

We’re almost there. Now we just need to write a file that will be responsible for instantiating our “Hello World” component and mount it into the DOM. While that sounds complicated, the React authors have done a fantastic job of making this super easy using a separate library called “react-dom”, which provides a special `render` function that handles all of the grunt work for us. All we do it is pass it our React component and the DOM node where we want to put it. First, install our dependency:

npm install --save react-dom

Ready for the next steps? Check out the short code example below for a basic implementation:

import React from 'react'
//this syntax is called destructuring.  This is assigns the variable render to the property with the same name exported by the react-dom package
import { render } from 'react-dom'

//import our first react component
//Note that because this is a relative path (and not a node_module), we start our path with `./`
//This assigns the variable App in this file to whatever was exported in the file whose path we're referencing
import App from './app/app.jsx';

//Here's where we use the render method we imported from the react-dom package to inject our component into the DOM
//we use the plain JS method document.getElementById() to use the div in our index.html file as our mount point
render(, document.getElementById("app"));

You can see that we import our app.jsx file (which has our “Hello World” module) and mount that into the DOM node with an id of “app”. Boom! Simple as that!

Putting all the pieces together

All we need to do now is run webpack to create our bundle. The easiest way to do that is add a “scripts” object to your package.json file and add a property with a key which will be the name of the command and a value which represents the command itself. See the example package.json below (notice all of our dependencies are stored here as well):

{
  "name": "bowst-about-react",
  "version": "1.0.0",
  "description": "Code base for the Bowst about React presentation",
  "main": " ",
  "scripts": {
    "build-dev": "webpack --config webpack.config.js"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/bowst/bowst-about-react.git"
  },
  "keywords": [
    "tutorial",
    "reactjs",
    "redux",
    "bowst"
  ],
  "author": "Drew Trafton",
  "license": "MIT",
  "bugs": {
    "url": "https://github.com/bowst/bowst-about-react/issues"
  },
  "homepage": "https://github.com/bowst/bowst-about-react#readme",
  "dependencies": {
    "react": "^0.14.7",
    "react-dom": "^0.14.7"
  },
  "devDependencies": {
    "babel-core": "^6.5.1",
    "babel-loader": "^6.2.2",
    "babel-preset-es2015": "^6.5.0",
    "babel-preset-react": "^6.5.0",
    "babel-preset-stage-0": "^6.5.0",
    "webpack": "^1.12.13"
  }
}

All you need to do is type `npm run dev` in the root of your project, and presto! A compiled and bundled app.bundle.js should be written to your dist folder.

Wrap up

Phew. If you made it this far, congratulations! We just covered a LOT of ground, but now our build system is all set up and we are free to start digging into the ins and outs of building an awesome React app. While it may seem like a lot of work just to get to Hello World, this is almost 100% boilerplate and can be used to start just about any project; that means you only have to write it one time.

Or, checkout the Bowst about React git repo. We’ll be using the the repo throughout this series, but cloning the “Step-2” branch provides great starting point for any React project.

Thanks for sticking with us up to this point, and get stoked for Bowst about React: Part 3 where we’ll be discussing how to make our app more interactive.

(Click here for the next post in this series.)

More Thoughts

Need help with your next digital project?

Click on that button and fill in the simple form.