/ Javascript

Boilerplate for Hapi.js, Web Socket, HTTP/2, React and Redux

Level - Advanced. Read Time ~ <10-15 minutes.

TL;DR

Github Repo

Running App

Boilerplate Goals

Recently I set myself the goal of learning and gaining a better understanding of the following technologies: -

  • NodeJS
  • Hapi.js
  • React
  • Redux
  • SSR (server side rendering)
  • Webpack
  • HTTP/2
  • Web Sockets
  • Travis
  • Heroku

Some of the above I've worked with before and others are new to me. So, I thought the best way of learning the above was to author a simple todo application (could have been "Hello world!"), demonstrating the aforementioned technologies. I took this further in the end and decided to create a boilerplate. My motivations for doing this are to hopefully help others setting up a Hapi application with similar components and tech stack. It's also a useful reference for myself on how to server side render React and Redux.

The repo can be found on Github -> https://github.com/blairg/hapi-socket-react-boilerplate

The boilerplate is not the most beautifully engineered application out there (happy for criticism of how I can improve it and sharpen my skills). My main intention was to focus on developing shiny features and use it as an educational project. Saying that, I have tried to instill good practices and opinions. I am a firm believer in separating your concerns and having a solid folder structure in place, to ensure your application is both maintainable and extensible.

Folder Structure

Once you clone the repo and dig into the code, which I advise you do. You will see the below folders in the root: -

  • src
    • client
    • server
    • shared
  • test
    • client
    • server
    • shared

My opinions here are to structure your test folders identically to your application folders. Others may disagree, but this synergy has worked for me. Having discipline and attention to detail allows your application to scale. It's also vital if you intend a small army of developers to support and develop it.

For this boilerplate, client refers to the React/Redux code and server refers to the Hapi code. Due this being an isomorphic JavaScript application, shared is the bridge between the client and server. All business logic and data access should live here.

Client Folder Structure

  • client
    • actionTypes
    • actions
    • components
      • containers
      • presentation
    • reducers
    • services
    • subscribers

actionTypes, actions, reducers house the Redux actions and logic. components stores the React components. I've decided to break this down even further, by having containers which houses components connected to the Redux store. The purpose of the presentation folder is to separate your component with there sole purpose to render data passed through their props. subscribers is used for connecting the React components to Web Sockets. Will go into more detail later on.

Server Folder Structure

  • server
    • controllers
    • models
    • plugins
    • repositories
    • routes
    • services

The thought behind the folder structure on the server allows the concerns to be separated. So the controllers folder will contain the concrete implementations. Such as in the index controller which server side renders the React and Redux. I recommend breaking this open to gain a better understanding. plugins is a nice to way to compartmentalise the Hapi plugins away from the main server implementation. routes is an interface to the controller controller implementation. This makes the server very testable as the routes can be mocked.

Shared

In my implementation I have very little in the shared folder. As this not a real world application and is contrived, there wasn't much scope for adding code here. But if you intend to create an isomorphic React/Hapi application, any code which is shared by the client and server should reside here. The rewards you reap from this separation will be great and force DRY principles.

Webpack

When I first started developing this application. I had one Webpack file. This quickly became unwieldy. So I split out into a client and server file to mirror the application separation. The main takeways from this are the following: -

  • Client - Targets web and creates a bundle.js in the public\js folder. Entry point is the app.jsx React component.
  • Server - Targets node and transpiles the ES6 Hapi implementation to ES5. With Node version 9, I'm actually not sure this is needed. Will have to check it out.

Docker

Got quite a primitive Dockerfile. This may need expanding for more advanced applications. The main gist of it is the following: -

  • Use an official NodeJS base image unless you have very good reason not to.
  • You'll see there are a few environment variables passed in. This allows the application to be 12 factor and can be run anywhere.

Travis/Heroku

You will see in the Travis yml where I actually push the built Docker image up to the Heroku container registry. My Travis file, serves the following purposes in order: -

  1. Use NodeJS environment running version 8.9.1.
  2. Run Docker.
  3. Install the npm modules from the package.json.
  4. Run the ESLint task.
  5. Run the code coverage using Mocha and Istanbul.
  6. Build the Dockerfile.
  7. Then for master branch on GitHub, login to the Heroku container regsitry and push up the built image.
  8. Heroku will then run a container based on this image.
  9. Push coverage stats to Coveralls.

Future Work

I'd like to learn/add the following to this repo: -

Questions

Any questions about this, leave them below and I'll try my best to respond.