Setting Up A Modern React Development Environment

10 February, 2017
post-banner

React is a JavaScript library, built by Facebook, for building user interfaces. React was initially built to solve the problem of building large applications with data that changes over time. React applications are built heavily with components that are able to manage their own state individually and can be composed together to build complex interfaces. React components are built with JavaScript, meaning that data is easily transported between components, without having to be managed by the DOM.

One of the many arguments against using React is that it there are a large number of tools and libraries available to run a simple web app, which sometimes leads to JavaScript fatigue. However, one of my favourite things about React is that you can make it as light-weight as you need, without having to include unnecessary tooling, yet are still able to build powerful applications. Then you are able to add a bunch of cool things on top of your apps, where it is needed - for example, adding Sass adding improved functionality to your CSS.

This article will serve as the first of a short series of React tutorials, designed to allow the reader to build and maintain complex React applications simply and gain a better understanding of the underlying concepts of React and the modern JavaScript development environment tools it uses. This first post will focus purely on getting a development environment up and running.


Required Tools and Prerequisites

We will be using a variety of tools to configure our modern React development environment, including:

  • React - JavaScript library for building user interfaces.
  • Webpack - A module bundler.
  • Babel - JavaScript compiler.
  • ES6 - Latest JavaScript standard (ECMAScript 6).
  • JSX - XML to JavaScript preprocessor (improves React components).
  • Yarn - Package manager (npm improved, caching).
  • Sass - CSS, with superpowers.

Before we begin our project, we need to make sure we have all of the pre-requisites installed - Node.js and Yarn. We can install the latest version of Node.js from their website. Yarn can be installed on a Mac, via the command line, using Homebrew. If you don't have Homebrew installed on your machine, you can install it using the command given on their home page.

$ brew update
$ brew install yarn

Creating a New Project with Yarn

Yarn is a fast and reliable package manager, that can be used in much the same ways as npm. The benefits of using Yarn here is that it caches every package that is installed, so reinstallations are much faster. It also offers more great features such as offline mode and guaranteed reliability across systems.

Let's begin by creating a new directory and initializing a project inside that directory using Yarn.

$ mkdir react-blog-demo && cd react-blog-demo
$ yarn init

Running yarn init will initialize a new project, much like running npm init, and ask for some default app configurations to be included in the package.json.


Bundling with Webpack

The next tool we need to install is Webpack. Webpack is a module bundler that will allow us to build our JavaScript files and bundle them to one place. We will then, eventually, inject this bundle into the body of our HTML. We will also install a webpack-dev-server extension which will allow us to run a small Express server and serve our bundles files.

We can use the yarn add command to install these packages. Yarn will then auto-generate a new lockfile - called yarn.lock - that stores the exact versions of your dependencies, much like npm-shrinkwrap.json, although Yarn's lockfile is not lossy and will allow previously installed versions to install much faster.

Once Webpack has been installed, we can create a webpack.config.js file to specify the configurations needed to bundle our app.

$ yarn add webpack webpack-dev-server
$ touch webpack.config.js

In this file, we need to define an entry point and an output for our files. The entry point is where the bundling process will start and should be the file where we will eventually render all of our React components.

// webpack.config.js

module.exports = {  
  context: __dirname + '/app',
  entry: './index.js',
  output: {
    path: __dirname + '/build',
    filename: 'bundle.js'
  },
}

Compiling ES6 and JSX with Babel

In order for our React application - written with ES6 and JSX code - to run and work in the browser, we will need to compile our code into a format that the browser can understand. For this, we will use Babel.

Babel is a JavaScript compiler that will allow us to compile our React, JSX, and ES6 syntax into browser-readable code.

We will need to install the core Babel package, a Babel loader for Webpack, and the presets used for compiling ES6 (ES2015) and JSX code. JSX is a preprocessor that adds XML syntax to JavaScript, allowing us to write more elegant React components.

Again, we will install these packages with Yarn. We also need to create a .babelrc file in the root of our application's directory to specify which Babel presets we are using. The --dev flag is included in this script to add the packages to our devDependencies, as they are only required during development of the app.

$ yarn add babel-core babel-loader babel-preset-es2015 babel-preset-react --dev
$ touch .babelrc

Once these packages have been installed, we can add our preset specifications to the new .babelrc file.

// .babelrc
{
  "presets": [ "es2015", "react" ]
}

The next step is to include the loaders we just installed to our webpack.config.js file. Webpack uses loaders to run transformations on the JavaScript code to allow our bundled code to include all of the functionality from our preprocessed syntax.

// webpack.config.js

module.exports = {  
  ...
  module: {
    loaders: [
      { test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/ },
      { test: /\.jsx?$/, loader: 'babel-loader', exclude: /node_modules/ }
    ]
  }
}

In our case, we are using the babel-loader to transform our ES6 syntax and React code, although there are many other loaders available, which you can check out via the Webpack documentation.


Serve the Bundled Files

To allow us to serve our bundled file, we need to specify the html-webpack-plugin to inject the bundle into the body of the HTML. Again, install this plugin with Yarn.

$ yarn add html-webpack-plugin

We, now, need to go back into our webpack.config.js file to create a new html-webpack-plugin object and set the name of the HTML file we want to inject our bundle into and where we are going to inject this.

const HtmlWebpackPlugin = require('html-webpack-plugin');  
const injectConfig = new HtmlWebpackPlugin({  
  template: './index.html',
  filename: 'index.html',
  inject: 'body'
});

module.exports = {  
  // previous webpack config
  ...
  plugins: [injectConfig]
}

Now, our development environment is ready, but we don't currently have anything to serve. We can create an index.html and an index.js file inside of an app directory to get started.

$ mkdir app && cd app
$ touch index.html index.js && cd ..

In our index.html file, we want to structure out a base HTML skeleton and in the index.js we can simply output a message to the console to verify that our setup is working.

// /app/index.html

<!DOCTYPE html>  
<html>  
  <head>
    <meta charset="utf-8">
    <title>React Development Environment</title>
  </head>
  <body>
    <div id="container"></div>
  </body>
</html>  

We don't need to include any <script> tags here, as the bundled JavaScript is automatically injected into the DOM via our Webpack plugins.

// /app/index.js

console.log('Hello World!');  

Finally, to serve our application, we can add a start script to the package.json and run yarn start.

// package.json

{
  ...
  "scripts": {
    "start": "webpack-dev-server"
  },
  ...
}
$ yarn start

Now, head over to localhost:8080 and open up the developer tools to check that the application has rendered correctly, and our message is logged to the console. We can also check the Network tab to see that the bundled files have been rendered at the request URL of http://localhost:8080/bundle.js.


Building Simple Components with JSX

Our development environment is now ready for us to start building a React application using JSX for components and the latest JavaScript standard.

Once more, we need to install React and a package called ReactDOM using Yarn. The react-dom package provides DOM-specific methods, such as render(), on top of the core React functionality.

$ yarn add react react-dom

Now we will create a folder inside of the app directory called components, where we will write all of the JSX components that we will render into our React application. Let's also create a React component called WelcomeMessage.jsx.

$ cd app && mkdir components && cd components
$ touch WelcomeMessage.jsx

So, let's start writing our React components. For this demo, we will write a simple component that displays a welcome message to the page. We will create more complex components in the coming posts, but for now, let's keep things simple.

// /app/components/WelcomeMessage.jsx

import React from 'react';

export default class WelcomeMessage extends React.Component {  
  render() {
    return (
      <header>
        <h1>Welcome to {this.props.data.title}.</h1>
      </header>
    )
  }
}

A React component must include a render() function so that React knows what the output of this component is. Here, we are simply returning a header that displays a welcome message, with a title passed in using something called props. This data will be passed down from the parent - here being the index.js file - which could be another component.

// /app/index.js
import React from 'react';  
import ReactDOM from 'react-dom';  
import WelcomeMessage from './components/WelcomeMessage.jsx';

const appData = {  
  title: 'React Demo App'
}

ReactDOM.render(  
  <WelcomeMessage data={appData} />, document.getElementById('container')
);

Here, we have created our main index file where we will import the ReactDOM class to render our components to the DOM. We have created an object called appData where we have set a title and have passed this to the rendered component using the single curly-brace syntax.

Now, Webpack should have recompiled our code so we can go back to localhost:8080, reload the page and see our component has been rendered.

rendered component

You can also check out all of the rendered components using the React Developer Tools extension for Chrome. This is a pretty cool way of keeping track of component state and what data is being rendered to which components.


Compiling Sass with Webpack Loaders

We now have a working React development environment, using JSX components. We could extend this environment further by adding some new loaders to our Webpack configuration to allow us to compile Sass code to improve our applications styling.

Sass is a CSS preprocessor that adds a lot of powerful functionality to our stylesheets including variables, nesting and mixins.

Let's install the necessary Webpack loaders with yarn, as well as node-sass which is required by the sass-loader as a peer dependency.

$ yarn add style-loader css-loader sass-loader node-sass

Again, we need to add a loader to our webpack.config.js loaders object. Here, you can specify which syntax version of Sass you would like to use (scss or standard sass), with scss being my preference and is set in the example.

module.exports = {  
...
  module: {
    loaders: [
      ...
      // previous loaders
      { test: /\.scss$/, loaders: ['style-loader', 'css-loader', 'sass-loader'], exclude: /node_modules/ }
    ]
  }
}

Now, we can create an app.scss file inside of our app directory to start writing some Sass. The final step to allow our compiled Sass to appear in our application is to import it to the entry file of our React app, alongside our components.

// /app/index.js

import React from 'react';  
import ReactDOM from 'react-dom';  
import WelcomeMessage from './components/WelcomeMessage.jsx';  
import SCSS from './styles/app.scss';  
...

Conclusions

As you can see, creating a modern React environment can require a lot of configurations, and it's easy to get lost in the wide array of tools available. Hopefully, this blog posts sheds some enlightenment on how to build a powerful, yet simple, environment fast, to allow more time to be spent building complex React components.

The next couple of blog posts in this series will focus more on React, and how to create a fairly complex application that acts as a blog. The blog will allow users to read, create, update and delete blog posts on the system by utilising React conventions, such as dynamic props, handling data changes with component state and synthetic events.

comments powered by Disqus