There is an excellent series of videos here which introduces React + Redux by building a basic Todo application.

I enjoyed these, but I wanted a way to apply the concepts to something more like a real world application. In the videos, all the source code is written in a single jsbin, with the important libraries included from CDNs, rather than being installed locally.

So, this post is my attempt to set up the same application in a way that would be more like a real application – i.e. with all the code in multiple files, libraries installed locally, and with a build system to compile everything for deployment.

I’m using the following tools/libraries;

  • NPM because it’s hard do anything Javascript-related without it
  • Babel so that we can use modern ES6 syntax in our JS code
  • React
  • Redux
  • React-Redux – a separate library that lets you tie react and redux together
  • Sass because I like it better than plain CSS
  • Webpack as the build system

You will need NodeJS installed (which provides the npm command).

Set up the project

mkdir redux-todo-app
cd redux-todo-app
npm init

Just hit enter in response to all the prompts, to accept the defaults and create the package.json file.

Install dependencies

npm install --save-dev webpack css-loader style-loader node-sass sass-loader

Configure the build system

Let’s start by getting a trivial “hello world” example to build.

mkdir -p app/src/js app/assets

Edit app/index.html and enter the following content;

<html>
  <head></head>
  <body>
    <script src="assets/index.js"></script>
  </body>
</html>

We’ll keep all our source code in app/src, and the compiled code will be in app/assets/index.js.

For now, all the index.html file does is load in the compiled javascript.

Edit app/src/js/root.js and enter the following content;

document.write("Hello, world!")

Now we need to configure our build system to compile app/src/root.js into app/assets/index.js

Edit webpack.config.js and add the following content;

module.exports = {
  entry: "./app/src/js/root.js",
  output: {
    path: __dirname + "/app/assets",
    filename: "index.js"
  },
};

This tells webpack that it should compile app/src/js/root.js and write the resulting JS code into app/assets/index.js

Now, we should be able to compile the code, like this;

./node_modules/.bin/webpack --progress --colors

The --progress and --colors options just make the output nicer, they’re not necessary.

You should see a nice, green message saying that app/assets/index.jshas been built.

Now, if you open app/index.html in your browser, you should see the “Hello, world!” message.

Rather than typing that webpack command every time, let’s add a build task to npm. Edit package.json and update the “scripts” section, to replace this;

"scripts": {
  "test": "echo \"Error: no test specified\" && exit 1"
},

…with this;

  "scripts": {
    "build": "./node_modules/.bin/webpack --progress --profile --colors"
  },

Now, we can compile our project like this;

npm run build

Use ES6

We want to use the latest ES6 syntax in our JS code, so we’ll need to add a transpiler to our project.

npm install --save-dev babel-core babel-loader

Now we need to tell webpack to use the transpiler on all .js files. Edit webpack.config.js and add a new section below the output section, like this;

module.exports = {
  entry: "./app/src/js/root.js",
  output: {
    path: __dirname + "/app/assets",
    filename: "index.js"
  },
  module: {
    loaders: [
      {
        test:      /\.js$/,
        loaders:   ['babel'],
        excludes:  /node_modules/

      }
    ]
  }
};

Let’s check that it’s working. Edit app/src/js/root.js and replace the contents with this;

var obj = {
  hello() {
    document.write("Hello, ES6 world!")
  }
}

obj.hello()

That’s ES6 function declaration syntax, so it will only work if it’s being transpiled correctly.

npm run build
open app/index.html

You should see “Hello, ES6 world!” in your browser.

Switch to React.js

Now we should be able to start using React components, so let’s try that.

Webpack needs another loader, to allow it to handle React’s JSX syntax

npm install --save-dev jsx-loader

We also need to install react and react-dom;

npm install --save-dev react react-dom

We need a DOM element at which to mount our React application. Edit app/index.html and replace the content with this;

<html>
  <head></head>
  <body>
    <div id="root"></div>
    <script src="assets/index.js"></script>
  </body>
</html>

We don’t need our app/src/js/root.js file anymore, so go ahead and delete that.

We’re going to keep our react components in their own directory hierarchy;

mkdir -p app/src/js/react/components

Edit app/src/js/react/components/root.jsx and add the following content;

var ReactDOM = require('react-dom')
var React    = require('react')

var Hello = require('./hello.jsx')

ReactDOM.render(
  <Hello greeting="Hello from React" />,
  document.getElementById('root')
)

This is a contrived example, just to demonstrate that we can pull in a separate react component from another file.

Edit app/src/js/react/components/hello.jsx and add the following content;

var React = require('react')

var Hello = React.createClass({
  render() {
    return <h1>{this.props.greeting}</h1>
  }
})

module.exports = Hello

The entrypoint of our project is now the root.jsx file, not the previous app/src/js/root.js file (which we’ve deleted), so we need to update webpack.config.js accordingly.

We also need to tell webpack to use the correct loader for our jsx files.

So, webpack.config.js should now look like this;

module.exports = {
  entry: "./app/src/js/react/components/root.jsx",
  output: {
    path: __dirname + "/app/assets",
    filename: "index.js"
  },
  module: {
    loaders: [
      {
        test:      /\.jsx$/,
        loaders:   ['babel', 'jsx'],
        excludes:  /node_modules/
      }
    ]
  }
};

Now, after you run the build, you should be able to view app/index.html in your browser and see “Hello from React”

The latest version of react allows us to simplify our Hello component. Because it just renders layout code based on its properties, we can replace the source of our hello.jsx file with this;

var React = require('react')

var Hello = (props) => (<h1>{props.greeting}</h1>)

module.exports = Hello

Starting from scratch, we’ve created a project that let’s us use ES6 and React.js with Webpack to build an application from individual React.js source files.

In the next post, we’ll look at building the Redux TODO application.

The source code for this post is available here.

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 )

Connecting to %s