How to create a universal ReactJS application with bare ReactJS

Previously in the adventures series

In the last post we decided to use following tools:

  1. Server side Javascript rendering – Express as the frontend server
  2. JS written in EcmaScript6 syntax – transpiling ES6 to ES5 using Babel loaded through Webpack
  3. Stylesheets written in Sass – transpiling SASS into CSS using sass-loader for Webpack
  4. All Javascript bundled in one file and all stylesheets bundled in another file – Webpack
  5. To minify assets (js, css) for production – Webpack
  6. A mechanism to watch for changes and transpile on the fly in development mode, to speed up workflow – Webpack
  7. Something to handle external dependencies – npm

Now we’ll learn how to set them up.


We will be creating a simple application for rating submissions. This is a really simplified version of the application we used for evaluating submissions for a RailsGirls event.

We need a form for creating new submissions:


We will display pending, evaluated and rejected submissions in separate but similar listings. All listings will have “first name” and “last name” columns, evaluated submissions will additionally have a “mark” column and rejected will have a “reason” column.


The last view that we need is the detailed submission view with the rating.



Firstly, let’s create package.json with the application dependencies:

Take a look at the ‘scripts’ key, it’s where we define the application tasks:

  • babel-node – to be able to write server.js file in ES6
  • start – for starting the server in development mode
  • build – for building production assets
  • production – for starting the server in production mode

To install the specified dependencies run npm install from the console, in the project directory.

Babel 6 requires also .babelrc file. Let’s create it then:

To start the server execute npm start.

To run in production mode execute npm run build first and then npm run production.


As you can see, we are running the server by executing server.js. We need to create it then:

Now let’s understand what different parts of this code do. This line creates an Express application:

Which we’ll configure later:

And then we start the actual server:


By default Express looks for the view to render in the views directory, so let’s create our index.ejs there:

There are two important things going on here. Firstly, this is the div where all of our app will be injected:

Secondly, we attach bundle.js (and bundle.css) only in development:

It’s important to do it only for development because in production we’ll have our assets minified with fingerprints (e.g. bundle-9bd396dbffaafe40f751.min.js). We’ll use the Webpack plugin to inject javascript and stylesheet bundles for production.


Development config

We included bundle.js, but we don’t have it yet, so let’s configure Webpack. Create a webpack directory and inside add the file development.config.js:

  • entry – defines entry points, the places from which Webpack starts bundling your application bundles (see the actual value in the shared config below – two entry points, one for stylesheets, one for javascript)
  • output – defines where the output file will be saved, how it will be named and how you can access it from the browser
  • module – defines loaders (for transpiling ES6, sass, etc.)
  • plugins – defines plugins (e.g. we use ExtractTextPlugin to extract the stylesheets to a separate output file)

Some parts will be shared between development and production, so I extracted them to default.config.js:

As you can see, here we configure:

  • how our bundle will be named,
  • on which port our server will start,
  • where our static assets will be served from (we use it in server.js),
  • entries which are the starting points for bundling,
  • loaders which we want to use:
    • babel-loader for ES6,
    • css-loader for ExtractTextPlugin
    • sass-loader for Sass

Production config

As I mentioned, for production we want assets to be minified and attached in HTML with fingerprints. That’s why we need a separate config:

Entry points

We specified entry points to our application as: src/application.js, css/application.scss – but we don’t have them yet. Let’s add them!

Create application.scss in the css directory:

Also download these two css files and save them in the css directory: main.scss, normalize.css. Then create an application.js file in the src directory:

This file is the entry point for our client side application. Notice the render method – it’s responsible for injecting your component tree into the specified element. For us, it’s the div with “app” id.


In application.js we imported the routes.js file that we don’t have yet.

Let’s create only two routes for now:

This means that when we go to /submissions/new, the SubmissionFormPage component will be rendered. But notice that the route is nested in the / route, which is assigned to the Main component.

It’s because we want Main to be some kind of layout component, with the menu, which will be visible all the time.

And all its child routes will be rendered inside the Main component thanks to the this.props.children directive:

And in SubmissionFormPage we would have the actual form:

Create the above components in src/components directory. As you can see, each ReactJS component has a render method which defines the HTML to be rendered. It’s not pure HTML, it’s HTML in Jsx syntax, to make it easy to write HTML in Javascript code.  

Connection to API

In the above file, you could also notice that when submitting the form we make a request to the backend API. We will use Axios to do this. Let’s create src/lib/Connection.js:

Displaying submissions

To check if everything works, it would be convenient to be able to see the pending submissions list, so let’s create PendingSubmissionsPage:

As you can see here, in componentDidMount we load submissions from the API and assign them to the local component state. Then we pass them to the SubmissionsList component which is responsible for rendering the table. SubmissionsList:


To have some kind of backend, you can clone and setup this very simplified backend app. Just follow instructions in the README.

Starting the app!

Now we can finally test if everything works. Run npm start in the console, and go to http://localhost:3000 in your browser.


Now we can implement the rating feature itself.
Let’s add SubmissionPage:

Again, in componentDidMount we load particular submissions from the API and assign them to the local component state. But the most important part is this:

We pass performRating handler as props to the Rate component:

And again pass performRating further, to the RateButton component, where we have actual rate value defined.

Here, finally, we have it bound to the onClick event because only here do we know the particular value for a rating – this.props.value

Thanks to that, when a user clicks a rate button, the performRating method defined in SubmissionPage is called and a request to the API is made.

Let’s add a route to the src/routes.js to be able to access the view:

That’s all!

We just created a simple application using bare React.
The important thing to notice is that we hold the state of the app in many places. In a more complicated application, this can cause a lot of pain :)

In the next post, we’ll update our app to use a more structured pattern for managing the state – Flux.

For now, you can practise a bit by adding the missing EvaluatedSubmissionsPage and RejectedSubmissionsPage.

The full code is accessible here.

See you next week!

  • Emi

    Thank you for this tutorial. The first part of the series was awesome and really helped me!
    I struggled with this one however. From the start I had to lock the dependencies versions (removed the “^”) because I was getting errors. There were also unmet dependencies (qs, deep-equal), a missing file (SubmissionLink.js).
    I fixed those and finally ended up with a bundle.js that unfortunately was not transpiled. I think that’s because I have Babel 6 installed globally. I tried to fix this too but I had to give up.
    As a suggestion, maybe you can lock the dependencies, specify the node/npm version to use, use Babel 6?
    I cloned your repository, no luck with that either (unmet dependencies). I have no doubt this worked for you, but I’m not sure what your environment was (I see the repo is older than the tutorial): which npm, which packages you had installed globally, etc, so that I can replicate and make this work.
    I know it’s a lot of work to put up a tutorial like this, so thank you again!

  • Anna Ślimak

    Thanks for your comment.
    I’ve checked this, and with node version 5.2.0 and npm version 3.3.12, indeed with removed “^” from package.json it works fine for me.
    The problem is when you want to use Babel 6. But I managed to make it working in this commit (thanks to really good BabelJS support via Slack ;]):

  • Anna Ślimak

    Please see also changed presets order (apparently order matters, as Babel support says):

    • Sokonglah lagi UMNgOk dan Barang Naik (BN).Pegi supermarket sekarang ni, tengok ape dah jadi dengan harga barang2 hari ni.Janganlah dok komplen pasal senamrobik ni, jangan nak spin2lah.Patutnya harga barang naik yg jadi keutamaan puak2 UMNgOk dan Barang Naik (BN) ni.Dahlah naikan harga minyak dibuat senyap2. Lepas tu cari point2 yg tak relevan utk tutup kelemahan mereka.Mari kita tumbangkan mereka dlm PRU13 nanti. Insyaallah.

  • This is one of the best tutorials on universal js with React that I found on the net. Thank you!!!! <3

    • Anna Ślimak

      Thank you : )