Bundle a React app with [email protected]


Imagine you have a React project with the following package.json:

{
  "dependencies": {
    "react": "15",
    "react-dom": "15"
  }
}

You have an index.html:

<!-- index.html -->
<html>
  <body>
    <div id="root"></div>
    <script src="main.js"></script>
  </body>
</html>

And your main.js looks like this:

// main.js
var React = require('react');
var ReactDOM = require('react-dom');

function Component(props) {
  return <h1>Hello, {props.name}!</h1>;
}

ReactDOM.render(
  <Component name='Mark' />,
  document.getElementById('root')
);

If you try to load the page, it fails because the browser doesn’t understand JSX syntax.

As a result, the code needs to be transpiled for it to be run in the browser. Here’s where webpack, a module bundler, comes in.

Dependencies

Install webpack:

$ npm install [email protected]

Then install babel-loader and babel-core, which will help with the transpilation:

To transpile JSX, you’ll need babel-preset-react:

$ npm install [email protected]

Configuration

Create your webpack config:

// webpack.config.js
module.exports = {
  entry: './main.js',
  output: {
    path: __dirname,
    filename: 'bundle.js'
  },
  module: {
    loaders: [
      {
        loader: 'babel-loader',
        query: {
          presets: ['react']
        },
        // match files based on pattern
        test: /\.js$/,
        // ignore files matching pattern
        exclude: /node_modules/
      }
    ]
  }
};

You could also create a build script in your package.json:

{
  "scripts": {
    "build": "webpack"
  }
}

To generate the bundle, run:

$ npm run build

Update index.html with the new file path:

<!-- index.html -->
<html>
  <body>
    <div id="root"></div>
    <script src="bundle.js"></script>
  </body>
</html>

When you refresh the page, the app now loads.

ES6

But what if you want to use ES6 syntax?

You’ll need babel-preset-es2015:

$ npm install babel-preset-es2015

Add the preset to your webpack config:

// webpack.config.js
module.exports = {
  // ...
  module: {
    loaders: [
      {
        loader: 'babel-loader',
        query: {
          // add `es2015` to presets
          presets: ['react', 'es2015']
        },
        // ...
      }
    ]
  }
};

Now you can refactor main.js with ES6:

// main.js
import React from 'react';
import { render } from 'react-dom';

const Component = ({ name }) => <h1>Hello, {name}!</h1>;

render(
  <Component name='Mark' />,
  document.getElementById('root')
);

Don’t forget to rebuild your bundle before refreshing the page:

$ npm run build

.babelrc

Alternatively, you can keep your babel presets in .babelrc:

{
  "presets": ["react", "es2015"]
}

Instead of defining them in your webpack config:

// webpack.config.js
module.exports = {
  // ...
  module: {
    loaders: [
      {
        loader: 'babel-loader',
        // query: {
        //   presets: ['react', 'es2015']
        // },
        test: /\.js$/,
        exclude: /node_modules/
      }
    ]
  }
};