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.