---
title: Setting Up Webpack for React and Hot Module Replacement
teaser: Set up Webpack for React and hot module replacement.
tags: web,javascript,es6,react
author: Blake Williams
published_on: 2015-06-19
---

Recently I've been toying with [React] and trying to find the best way to get up
and running. After a lot of trial and error I decided to go with [webpack]
as my build tool and share what I've learned from my experience with it.

[React]: https://facebook.github.io/react/
[webpack]: http://webpack.github.io/

## Initializing a project

Since React doesn't have any tools to generate and manage projects, it's up to
us to set everything up. We need to create the directory, initialize Git, and
initialize npm.

<kbd>
mkdir react-project && cd react-project
<br />
git init
<br />
npm init
</kbd>

After running `npm init`, it's a good idea to add `"private": true` to
`package.json` so we can't accidentally publish our project to npm.

## Setting up webpack

Webpack is the build tool that takes our application code and generates static
assets as well as a development server. Webpack has several advantages over
other build tools: for example, it strips out unused code, supports hot module
replacement, and is easily configured.

To get started we need to install webpack both globally and in the project. We
install it globally to make the `webpack` command available and we install it
locally so we can specify which version of webpack the project should use
instead of relying on the global install.

<kbd>
npm install webpack --global
<br />
npm install webpack --save-dev
</kbd>

### Basic configuration

Let's start with a basic configuration in `webpack.config.js` and build on it as
we go.

```javascript
module.exports = {
  context: __dirname + "/app",
  entry: "./app.js",

  output: {
    filename: "app.js",
    path: __dirname + "/dist",
  },
}
```

At the moment we're telling webpack that our application lives in the `app`
directory and the entry point to our application is `app.js`. We also tell
webpack to output the resulting JavaScript in `dist/app.js`.

We can add a basic `app/app.js` to make sure it's working:

```javascript
console.log("webpack rocks!");
```

Now we can run `webpack` again and we can see that it creates `dist/app.js` and
includes the code that we wrote.

### Adding loaders

At the moment our configuration is basically just copying our file to the `dist`
folder. The real power of webpack is the loaders that it provides. In this case
we're going to use loaders to send our code through [Babel] and transform our
[JSX] into JavaScript.

[Babel]: http://babeljs.io/
[JSX]: https://facebook.github.io/react/docs/jsx-in-depth.html

Fortunately the Babel loader supports transforming both ES2015 and JSX which
means we can get away with using a single loader instead of requiring both the
`babel-loader` and the `jsx-loader`.

We can install the babel loader with the following command:

<kbd>npm install babel-loader --save-dev</kbd>

To use the loader we need to add a `loaders` object nested in a `module` object
in `webpack.config.js`.

```javascript
module: {
  loaders: [
    {
      test: /\.js$/,
      exclude: /node_modules/,
      loaders: ["babel-loader"],
    }
  ],
},
```

Webpack accepts an array of loader objects which specify `loaders` to apply to
files that match the `test` regex and exclude files that match the `exclude`
regex. In this case we're applying the `babel-loader` to all files with a `.js`
extension that aren't in `node_modules`.

If we run `webpack` we'll see that webpack still bundles our JavaScript
successfully.

## Writing React components

Now that we have a basic webpack configuration set up we can add React to the
mix. Let's install React and write a simple greeting component.

First we need to install React:

<kbd>npm install react --save</kbd>

Now we can write a greeting component in `app/greeting.js`:

```javascript
import React from "react";

export default React.createClass({
  render: function() {
    return (
      <div className="greeting">
        Hello, {this.props.name}!
      </div>
    );
  },
});
```

Inside `app/app.js` we need to import our new greeting component and render it
on the page.

```javascript
import React from "react";
import Greeting from "./greeting";

React.render(
  <Greeting name="World"/>,
  document.body
);
```

We're using [ES6 modules] to import React and the greeting component we just
wrote. The first argument to `React.render` is using JSX to render our
`Greeting` component with the name property being passed in as `World`.

[ES6 modules]: http://babeljs.io/docs/learn-es2015/#modules

JSX is just a more friendly syntax for rendering React components. We could
write it in JavaScript too. When compiled, the `babel-loader` will turn our JSX
into the following:

```javascript
React.createElement(Greeting, {name: "World"})
```

Now when the application is loaded our `Greeting` component will be rendered
with "World" passed in as the `name` property.

### Adding an index page

React is ready to go, but we need a page to render the content. Let's create a
basic page in `app/index.html`.

```html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Webpack + React</title>
  </head>
  <body></body>
  <script src="app.js"></script>
</html>
```

Webpack needs to copy this file over to our `dist` folder for us to use it which
means we'll need to modify our `entry` property in our webpack config and add an
additional loader.

```javascript
entry: {
  javascript: "./app.js",
  html: "./index.html",
},
```

To actually copy the file over we need the `file-loader` package, which is a
loader that copies files.

<kbd>npm install file-loader --save-dev</kbd>

In our `webpack.config.js` file below our first loader object, we can add a
loader object for the index page:

```javascript
{
  test: /\.html$/,
  loader: "file?name=[name].[ext]",
},
```

Run `webpack` one more time and open up the `dist/index.html` file in a browser
and you can see our greeting component rendered on the page.

## Setting up the webpack dev server

It's pretty tedious to continue having to type `webpack` and refresh the page
each time we make a change. Lucky for us webpack has another module that
provides a development server.

We need to install [webpack-dev-server] both locally and globally for the same
reasons we installed webpack that way. We can install it with the following
command:

[webpack-dev-server]: http://webpack.github.io/docs/webpack-dev-server.html

<kbd>
npm install webpack-dev-server --global
<br />
npm install webpack-dev-server --save-dev
</kbd>

To run the dev server run `webpack-dev-server` and visit
`http://localhost:8080`.

### Hot module replacement

Using the `webpack-dev-server` we can set up hot module replacement with React.
This means whenever we modify a component and save the file webpack will replace
the module on the page without reloading, without losing component state.

To get hot reloading working with React we have to install `react-hot-loader`:

<kbd>
npm install react-hot-loader --save-dev
</kbd>

To use the `react-hot-loader` loader, we can just prepend it to the `loaders`
array in our first loader object.

```javascript
{
  test: /\.js$/,
  exclude: /node_modules/,
  loaders: ["react-hot", "babel-loader"],
},
```

Whenever matching files are found they're now passed through `react-hot` first
and then through `babel-loader`.

Finally we need to run `webpack-dev-server` with two new options:

<kbd>webpack-dev-server --hot --inline</kbd>

Now when serving our project webpack injects JavaScript code that connects to
the server and waits for module updates to be pushed. When an update is received
the module is replaced.

It's worth noting that *not all* modules can be replaced. The code in
`app/app.js` cannot be reloaded and will cause a full page reload but changing
the `Greeting` component will trigger a hot module replacement.

To see it in action we can modify our greeting component by wrapping the text
in an `h1` tag. Now the `render` function in `app/greeting.js` will look like
this:

```javascript
render: function() {
  return (
    <div className="greeting">
      <h1>Hello, {this.props.name}!</h1>
    </div>
  );
},
```

When you save the file you'll see the page update automatically without a page
reload.

For convenience we can add an [npm script] to run the server with the `--hot
--inline` flags so we don't have to type them out each time.

[npm script]: https://docs.npmjs.com/misc/scripts

We can add the command under the `scripts` object in `package.json`:

```javascript
"scripts": {
  "start": "webpack-dev-server --hot --inline"
},
```

To run the server all we have to do is run `npm start` and we have a development
server with hot module replacement up and running.

## What's next?

* Learn more about [webpack loaders].
* Dive deeper into React's [JSX] templates.
* Learn about building React applications with [Flux], a design pattern by
  Facebook.

[webpack loaders]: http://webpack.github.io/docs/loaders.html
[JSX]: https://facebook.github.io/react/docs/jsx-in-depth.html
[Flux]: https://facebook.github.io/flux/docs/overview.html
