Tutorial - Setting Up a Single Page React Web App with React-router and Webpack

February 27, 2015

Note: this tutorial assumes React 0.13 and React-Router 0.13. Updates coming soon for the new versions

There are many different ways of setting up a new project with React and Node.js. A Google search leads to a ton of different tutorials about isomorphism, Express/Koa, and running full Node.js servers.

While there are many advantages of structuring your web app this way, it also leads to a much longer set up time, increased complexity, and more difficult deployment. Another way of doing it is by simply bundling all your Javascript files and other assets, and serving them as static files. In that case, your web app is essentially just a simple index.html that has links to your assets. The most impactful tradeoff of this method is that your users have to download the whole bundle before your app is usable.

I would argue that this is the simplest way of getting a reasonably sized React project started without spending too much time setting up. This is a tutorial describing how to do this from an empty project to an app with build tools, React, routing, and your first component. It will use Webpack, Babel for es6, React.js, and React-router.

Initializing NPM and the Project

Starting with an empty directory for our project, we are gonna initialize a package.json to handle our package dependencies, and build commands. To do so, type the following and answer the corresponding questions:

$ npm init

Next, we will install the required packages and save them to the package.json. This allows for any body to quickly install all the required packages for your project by just typing npm install. For the first time, however, we will have to explicitly tell NPM what packages we need:

$ npm install --save-dev react webpack react-router react-hot-loader webpack-dev-server babel-loader

With the create packages installed, we will now create the directories we will need for the project.

$ mkdir js css && touch index.html webpack.config.js

That’s it!

Webpack

Webpack is a module bundler that takes all your code and generates bundled static files. It is these files that will be ultimately included on our deployed web app.

Open the empty webpack.config.js, and paste in the following code.

var webpack = require('webpack');
module.exports = {
    entry: [
      'webpack/hot/only-dev-server',
      "./js/app.js"
    ],
    output: {
        path: __dirname + '/build',
        filename: "bundle.js"
    },
    module: {
        loaders: [
            { test: /\.js?$/, loaders: ['react-hot', 'babel'], exclude: /node_modules/ },
            { test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader'},
            { test: /\.css$/, loader: "style!css" }
        ]
    },
    plugins: [
      new webpack.NoErrorsPlugin()
    ]

};

There are four main sections to this configuration file: entry, output, module, plugins.

The entry section tells webpack where the entry file is, and we have the development server for webpack and react-hot-loader. The output section is where the bundled files should go when we build our app. In this case, the files will be in /build/bundle.js. The module section is the most crucial part of webpack. This is where you add/remove loaders based on what you need webpack to bundle for you. The two main ones we are using are react-hot and babel. The line including react-hot and babel are for our development server to use es6 Javascript while hot loading. The babel-loader for when we build and generate static files that are to be es6-ified. Lastly, we generate our style.css as an example of how to include other types of static files. This is where you would put different loaders such as a sass-loader or one for image assets. The last section is plugins and include different type of webpack plugins. The NoErrorsPlugin is for hot loader to not automatically reload if there are errors in the code (this is useful for keeping state). There are many different webpack plugins that can aid your development.

With the configuration set up, return to package.json and change your scripts section to reflect the following:

  "scripts": {
    "start": "webpack-dev-server --hot --progress --colors",
    "build": "webpack --progress --colors"
  }

It is key here to note that when doing development work you will run npm start which will spin up a webpack development server. You will visit your site by going to localhost:8080/webpack-dev-server/#/ in your browser. The server has to be running for you app to work this way. For deployment, you will use npm run build which simply generates your assets in /build. To view your app this way (as to simulate deployment), you will have to edit the newly created index.html.

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>New React App</title>
  </head>
  <body>
    <section id="react"></section>
    <script src="bundle.js"></script>
  </body>
</html>

Now, just open this file in Chrome and it will pull in the newly created bundle.js from that was created from npm run build. You can include any other assets here such as Bootstrap, etc.

React-router

With all the setup nearly done, we will finally create the app.js file which marks the entry point of our web app. In your js folder, open an empty file called app.js. Paste in the following.

import React from 'react';
import Router from 'react-router';
import { DefaultRoute, Link, Route, RouteHandler } from 'react-router';

import LoginHandler from './components/Login.js';

let App = React.createClass({
  render() {
    return (
      <div className="nav">
        <Link to="app">Home</Link>
        <Link to="login">Login</Link>

        {/* this is the importTant part */}
        <RouteHandler/>
      </div>
    );
  }
});

let routes = (
  <Route name="app" path="/" handler={App}>
    <Route name="login" path="/login" handler={LoginHandler}/>
  </Route>
);

Router.run(routes, function (Handler) {
  React.render(<Handler/>, document.body);
});

The first thing that needs to be done is that we import the necessary packages from react and react-router. We also import a file, that will be made shorty, called Login.js that is our Login React component. We then use React to create the App class. In this case, it is simple nav bar that will appear on all child components. We simply Link to our routes: app and login. React-router is then initialized by calling the RouteHandler component.

Outside the created App, we define our routes and their respective Handlers (React components). We define the root path as app and all other routes will be children of app. In this case, we added login as an example of getting to the page where a user would login into the app.

Lastly, we have React-router mount everything we need onto document.body. This is how index.html turns into our React app!

Components

At this point, nearly everything is set up. We just have to start adding components. So, in our /js folder, create a components folder. Here is where we will add our Login.js to insure that react-route is working.

import React from 'react';

let Login = React.createClass({

  render() {
    return(<div>Welcome to login</div>);
  }
});

export default Login;

It is just a simple React component that displays “Welcome to Login”. We are now free to test the app. Run npm start in your project’s directory, and visit http://localhost:8080/webpack-dev-server/#.

You should see our “nav bar” which has two links to Home and Login. If you click on Login, it should show the React component we just made!

If you were successful, you are now ready to start building your React app. Everything has been set up, and components can be added and visited using react-router. If you were looking to use Flux on your project (which is highly recommended), you are open to use any structure you want in the js folder. Facebook’s Chat example for Flux, however, is a very nice solution that fits well with our folder structure.

Deployment

There are manys to deploy your web app, but one of the nice things about webpack is can simply use the bundled files you created. One way of doing this is simply uploading the bundled files to a CDN, and then hosting the index.html we created earlier as the website. You would just have to update the paths to the scripts appropriately.

If you are interested in learning about how this differs from an isomorphic app, visit my tutorial on how simple it can be

Please feel free to email me or reach out to me on Twitter if you have any questions or comments!


Written by Joseph Furlott who lives and works in Brooklyn, New York. I am a software engineer that specializes in designing and building web applications using React. I work at Datadog as a software engineer.

© 2022
jmfurlott@gmail.com