A New Stack for 2016: Getting Started with React, ES6 and Webpack

A lot has changed in the last few years when it comes to implementing applications using JavaScript. Node JS has revolutionized how many of us create backend apps, React has become a widely-used standard for creating the frontend, and ES6 has come along and completely transformed JavaScript itself, largely for the better.

All of this brings new capabilities and opportunities, but also new challenges when it comes to figuring out what’s worth paying attention to, and how to learn it. Today we’ll look at how to set up my personal take on a sensible stack in this new world, starting from scratch and building it up as we go. We’ll focus on getting to the point where everything is set up and ready for you to create the app.

The stack we’ll be setting up today is as follows:

  • React – to power the frontend
  • Babel – allows us to use ES6 syntax in our app
  • Webpack – builds our application files and dependencies into a single build

Although we won’t be setting up a Node JS server in this article, we’ll use npm to put everything else in place, so adding a Node JS server using Express or any other backend framework is trivial. We’re also going to omit setting up a testing infrastructure in this post – this will be the subject of the next article.

If you want to get straight in without reading all the verbiage, you can clone this github repo that contains all of the files we’re about to create.

Let’s go

The only prerequisite here is that your system has Node JS already installed. If that isn’t the case, go install it now from http://nodejs.org. Once you have Node, we’ll start by creating a new directory for our project and setting up NPM:

mkdir myproject
npm init

The npm init command takes you through a short series of prompts asking for information about your new project – author name, description, etc. Most of this doesn’t really matter at this stage – you can easily change it later. Once that’s done you’ll find a new file called package.json in your project directory.

Before we take a look at this file, we already know that we need to bring in some dependencies, so we’ll do that now with the following terminal commands:

npm install react –save
npm install react-dom –save
npm install webpack –save-dev

Note that for the react dependency we use –save, whereas for webpack we use –save-dev. This indicates that react is required when running our app in production, whereas webpack is only needed while developing (as once webpack has created your production build, its role is finished). Opening our package.json file now yields this:

{
   "name": "myproject",
   "version": "1.0.0",
   "description": "",
   "main": "index.js",
   "scripts": {
       "test": "echo \"Error: no test specified\" && exit 1"
   },
   "author": "",
   "license": "ISC",
   "dependencies": {
     "react": "^0.14.7",
     "react-dom": "^0.14.7"
   },
   "devDependencies": {
     "webpack": "^1.12.14"
   }
 }

This is pretty straightforward. Note the separate dependencies and devDependencies objects in line with our –save vs –save-dev above. Depending on when you created your app the version numbers for the dependencies will be different, but the overall shape should be the same.

We’re not done installing npm packages yet, but before we get started with React and ES6 we’re going to get set up with Webpack.

Setting up Webpack

We’ll be using Webpack to turn our many application files into a single file that can be loaded into the browser. As it stands, though, we don’t have any application files at all. So let’s start by creating those:

mkdir src
touch src/index.js
touch src/App.js

Now we have a src directory with two empty files. Into App.js, we’ll place the following trivial component rendering code:

var App = function() {
  return "<h1>Woop</h1>";
};

module.exports = App;

All we’re doing here is returning an HTML string when you call the App function. Once we bring React into the picture we’ll change the approach a little, but this is good enough for now. Into our src/index.js, we’ll use:

var app = require('./App');
document.write(app());

So we’re simply importing our App, running it and then writing the resulting HTML string into the DOM. Webpack will be responsible for figuring out how to combine index.js and App.js and building them into a single file. In order to use Webpack, we’ll create a new file called webpack.config.js (in the root directory of our project) with the following contents:

var path = require('path');
var webpack = require('webpack');

module.exports = {
  output: {
    filename: 'bundle.js'
  },
  entry: [
    './src/index.js'
  ]
};

This really couldn’t be much simpler – it’s just saying take the entry point (our src/index.js file) as input, and save the output into a file called bundle.js. Webpack takes those entry file inputs, figures out all of the require(‘…’) statements and fetches all of the dependencies as required, outputting our bundle.js file.

To run Webpack, we simply use the `webpack` command in our terminal, which will do something like this:

webpack

webpack terminal output

As we can see, we now have a 1.75kb file called bundle.js that we can serve up in our project. That’s a little heavier than our index.js and App.js files combined, because there is a little Webpack plumbing that gets included into the file too.

Now finally we’ll create a very simple index.html file that loads our bundle.js and renders our app:

<html>
  <head>
    <meta charset="utf-8">
  </head>
  <body>
    < div id="main"></div>
    < script type="text/javascript" src="bundle.js" charset="utf-8"></script>
  </body>
 </html>

Can’t get much simpler than that. We don’t have a web server set up yet, but we don’t actually need one. As we have no backend we can just load the index.html file directly into the browser, either by dragging it in from your OS’s file explorer program, or entering the address manually. For me, I can enter file:///Users/ed/Code/myproject/index.html into my browser’s address bar, and be greeted with the following:

woop

Our first rendered output

Great! That’s our component being rendered and output into the DOM as desired. Now we’re ready to move onto using React and ES6.

React and ES6

React can be used either with or without ES6. Because this is the future, we desire to use the capabilities of ES6, but we can’t do that directly because most browsers currently don’t support it. This is where babel comes in.

Babel (which you’ll often hear pronounced “babble” instead of the traditional “baybel”) a transpiler, which takes one version of the JavaScript language and translates it into another. In our case, it will be translating the ES6 version of JavaScript into an earlier version that is guaranteed to run in browsers. We’ll start by adding a few new npm package dependencies:

npm install babel-core –save-dev
npm install babel-loader –save-dev
npm install babel-preset-es2015 –save-dev
npm install babel-preset-react –save-dev
npm install babel-plugin-transform-runtime –save-dev

npm install babel-polyfill –save
npm install babel-runtime –save

This is quite a substantial number of new dependencies. Because babel can convert between many different flavors of JS, once we’ve specified the babel-core and babel-loader packages, we also need to specify babel-preset-es2015 to enable ES6 support, and babel-preset-react to enable React’s JSX syntax. We also bring in a polyfill that makes available new APIs like Object.assign that babel would not usually bring to the browser as it requires some manipulation of the browser APIs, which is something one has to opt in to.

Once we have these all installed, however, we’re ready to go. The first thing we’ll need to do is update our webpack.config.js file to enable babel support:

var path = require('path');
var webpack = require('webpack');

module.exports = {
  module: {
    loaders: [
      {
        loader: "babel-loader",
        // Skip any files outside of your project's `src` directory
        include: [
          path.resolve(__dirname, "src"),
        ],
        // Only run `.js` and `.jsx` files through Babel
        test: /\.jsx?$/,
        // Options to configure babel with
        query: {
          plugins: ['transform-runtime'],
          presets: ['es2015', 'react'],
        }
      }
    ]
  },
  output: {
    filename: 'bundle.js'
  },
  entry: [
    './src/index.js'
  ]
};

Hopefully the above is clear enough – it’s the same as last time, with the exception of the new module object, which contains a loader configuration that we’ve configured to convert any file that ends in .js or .jsx in our src directory into browser-executable JavaScript.

Next we’ll update our App.js to look like this:

import React, {Component} from 'react';

class App extends Component {
  render() {
    return (<h1>This is React!</h1>);
  }
}
export default App;

Cool – new syntax! We’ve switched from require(”) to import, though this does essentially the same thing. We’ve also switched from `module.exports = ` to `export default `, which is again doing the same thing (though we can export multiple things this way).

We’re also using the ES6 class syntax, in this case creating a class called App that extends React’s Component class. It only implements a single method – render – which returns a very similar HTML string to our earlier component, but this time using inline JSX syntax instead of just returning a string.

Now all that remains is to update our index.js file to use the new Component:

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

ReactDOM.render(<App />, document.getElementById("main"));

Again we’re using the import syntax to our advantage here, and this time we’re using ReactDOM.render instead of document.write to place the rendered HTML into the DOM. Once we run the `webpack` command again and refresh our browser window, we’ll see a screen like this:

react-heading

Now we’re cooking with gas. Or, at least, rendering with React

Next Steps

We’ll round out by doing a few small things to improve our workflow. First off, it’s annoying to have to switch back to the terminal to run `webpack` every time we change any code, so let’s update our webpack.config.js with a few new options:

module.exports = {
  //these remain unchanged
  module: {...},
  output: {...},
  entry: [...],

  //these are new
  watch: true,
  colors: true,
  progress: true
};

Now we just run `webpack` once and it’ll stay running, rebuilding whenever we save changes to our source files. This is generally much faster – on my 2 year old MacBook Air it takes about 5 seconds to run `webpack` a single time, but when using watch mode each successive build is on the order of 100ms. Usually this means that I can save my change in my text editor, and by the time I’ve switched to the browser the new bundle.js has already been created so I can immediately refresh to see the results of my changes.

The last thing we’ll do is add a second React component to be consumed by the first. This one we’ll call src/Paragraph.js, and it contains the following:

import React, {Component} from 'react';

export default class Paragraph extends Component {
  render() {
    return (<p>{this.props.text}</p>);
  }
}

This is almost identical to our App, with a couple of small tweaks. First, notice that we’ve moved the `export default` inline with the class declaration to save on space, and then secondly this time we’re using {this.props} to access a configured property of the Paragraph component. Now, to use the new component we’ll update App.js to look like the following:

import React, {Component} from 'react';
import Paragraph from './Paragraph';

export default class App extends Component {
  render() {
    return (
      < div className="my-app">
        <h1>This is React!!!</h1>
        <Paragraph text="First Paragraph" />
        <Paragraph text="Second Paragraph" />
      </div>
    );
  }
}

Again a few small changes here. First, note that we’re now importing the Paragraph component and then using it twice in our render() function – each time with a different `text` property, which is what is read by {this.props.text} in the Paragraph component itself. Finally, React requires that we return a single root element for each rendered Component, so we wrap our <h1> and <Paragraph> tags into an enclosing <div>

By the time you hit save on those changes, webpack should already have built a new bundle.js for you, so head back to your browser, hit refresh and you’ll see this:

react-with-paragraphs

The final rendered output

That’s about as far as we’ll take things today. The purpose of this article was to get you to a point where you can start building a React application, instead of figuring out how to set up all the prerequisite plumbing; hopefully it’s clear enough how to continue from here.

You can find a starter repository containing all of the above over on GitHub. Feel free to clone it as the starting point for your own project, or just look through it to see how things fit together.

In the next article, we’ll look at how to add some unit testing to our project so that we can make sure our Components are behaving as they should. Until then, happy Reacting!

11 Responses to A New Stack for 2016: Getting Started with React, ES6 and Webpack

  1. Rosemary spencer says:

    If only I could understand a word of this😜

  2. Great introducing article on React. Thanks!

  3. Aaron Conran says:

    Very similar to my personal starting repo that I setup earlier today. The one thing I would recommend is to use to install babel-plugin-react-require. This will allow you to eliminate importing the “React” variable at the top of every file that uses JSX. You’ll notice that even if your code never refers to “React” it will still break because when the JSX is converted to raw JS it will inject/assume that variable is present.

    Another comment is it’s worthwhile to abstract your babel settings into a .babelrc that will automatically get picked up and used rather than hardcoding it into your webpack.config.js.

    • Ariya says:

      In addition to that, I would also argue that TypeScript as an ES6 transpiler is an excellent alternative to Babel. It’s straightforward to use (one npm package) and the tooling is fabulous (VS Code, tslint, …). It’s perfectly fine to treat TypeScript as a full-featured and powerful ES6 transpiler and ignore everything else (type annotation etc).

  4. edspencer says:

    Good point Aaron – I’ll be sure to point out why React needs to be imported in the next article! It stumped me a few times initially; thanks for pointing out why it needs to be included even if it doesn’t appear to be used.

  5. Ed, do you use ReactJS in C3 IoT?
    As I know you did self JS framework in company on base of JQuery and less.
    Did you switch to ReactJS?
    Could you please write more about current stack if possible? 🙂

    • edspencer says:

      I actually moved on from C3 to Palo Alto Networks a couple of months back. Last I knew C3 was not yet using React, but we do use it for one of our new products at PAN (though several of our products still use Ext JS).

      There are several more posts lined up in various stages of completion 🙂 Next up is a post about how to set up a decent React component testing stack (harder than it should be), followed by a few posts on Redux.

    • edspencer says:

      It sounds like you’re trying to get hot reloading working. I banged my head against that wall for many hours before finally giving up (having webpack-dev-server running alongside an existing Express backend seems possible but no matter what I did I could not achieve it). The nearest thing I did find was https://github.com/gaearon/react-hot-boilerplate, which did work for me (though again I could not get it to function in tandem with my existing Node backend).

  6. Les says:

    Ed,

    Do consider this development stack a competitor to Ext JS? I think most developers would be better served by using Ext JS especially if building complex desktop style applications which rely on a large number components which Ext JS provides out of the box.

    What component library would you use with the development stack that you propose? I don’t think you’d expect others to build these components from scratch. I think you know very well that this would be a major effort.

    Secondly, would is your take on Angular 2 vs React?

    • edspencer says:

      No I don’t consider it a direct competitor to Ext JS – what I’ve described above is a small and simple starting point for a fully custom UI; it has none of the components or app architecture offered by Ext JS.

      In terms of what component library I’d suggest running on top of React, I’m afraid I don’t have a great answer for you. I’ve been happy enough just creating my own components as needed, but I agree this is not something everyone will be happy doing. Might be a gap in the market there…

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: