CrocoDillon / universal-react-redux-boilerplate

Step by step creation of a Universal React + Redux Boilerplate
Other
176 stars 33 forks source link

Universal React + Redux Boilerplate

NPM Version Build Status dependencies Status devDependencies Status Package Quality

Boilerplate with all the good stuff but without the JavaScript fatigue. Made by Dillon de Voor, follow me for updates and more!

Includes Koa 2, React 15, Webpack 2 and React Hot Loader 3. See section “Feature rich” for what other awesome features you can expect.

This is v2 of this boilerplate. See the v1 branch for the previous version.

Why another boilerplate?

Because this boilerplate is different than most boilerplates out there. Most boilerplates will just give you a rather complex starting point but not how they got to that starting point. Ever heard ot JavaScript fatigue? These boilerplates are not helping.

This boilerplate attempts to solve this by providing a series of logical steps to build your own boilerplate. Of course you’re free to just use this one too but I encourage you to at least take a look at each step to get a basic understanding of each part of the app.

The steps are in the form of commits and I really hope this makes React and all the tooling around React more comprehensible, even for beginners. If you like it, please spread the word!

Feature rich

Despite my aim to make this the easiest understandable boilerplate you will find lots of features useful for development and for production. The finished boilerplate will include the following:

Let’s get started!

git clone https://github.com/CrocoDillon/universal-react-redux-boilerplate.git
cd universal-react-redux-boilerplate
npm install

Running the development server

npm run dev

Running the production server

npm run build
npm start

Checking code quality

Run ESLint, Mocha and Flow:

npm run check

Or separately:

npm run lint
npm run test
npm run flow

Or even lint JS and CSS separately:

npm run lint:js
npm run lint:css

Step by step

Here is a summary of each step, where each step also represents one commit. Each step is like a milestone that brings us closer to the finished boilerplate. Feel free to modify to your needs!

React with JSX, transpiled by Babel and bundled with Webpack

You might want to use ECMAScript 6 (and beyond) features like modules, at the very least you will want to use JSX (React just isn’t the same without it). To be able to do that we will transpile our code using Babel. In addition to Babel we will use Webpack to create a bundle for the client.

Because the options passed to Babel need to be different for the server and the client, we won’t include a .babelrc options file. Instead, we pass the options to babel-register for the server and in the Webpack config for the client. This might lead to some duplication but makes the separation more verbose.

To make use of a Webpack 2 feature called tree-shaking, we have to use the Babel preset es2015-webpack so Babel doesn’t transform ES6 modules to CommonJS.

Oh and do yourself a favor, make it a habit to always specify displayName and propTypes (if applicable) to React components.

Setting up ESLint

Before starting your project it’s probably a good idea to set up some rules about code style. ESLint is awesome to enforce these rules because it’s pluggable and fully configurable. Linting is not about “best practices” and other people’s opinions, it’s about code style consistency, maintainability and preventing errors. The rules are up to you or your team, ESLint will do the rest.

The .eslintrc.js file in this boilerplate is absolutely huge but don’t be intimidated by it. We could go the easy way and extend eslint:recommended or for example eslint-config-airbnb but remember, it’s about your rules. I included every single standard ESLint rule and every single eslint-plugin-react rule whether they are enabled or not. That way all the rules are in one place which makes it easier to make them fit your needs.

Setting up Mocha and Enzyme

It’s also a good idea to start testing early. We use Mocha and Enzyme (which provides some nice testing utilities for React), along with Chai as assertion library. Even though we are not using it yet I also added Sinon to create spies, stubs and mocks and some Chai plugins to make assertions more expressive.

Files containing tests are named *.spec.js and kept as close to the module they are testing as possible. If there are more than a few test files in one directory it can still be a good idea to put them in a subdirectory to keep things clean.

Setting up Flow

The last step in ensuring code quality is static type checking with Flow. This might require some annotations in your code which will be stripped out by a Babel plugin included in the React preset. Not everyone will be comfortable with that so let’s call this step optional.

Now is a good time to add continuous integration which will run all our checks whenever we push to GitHub. And the badges... they are awesome!

Development strategy using Webpack middleware and React Hot Loader

Restarting the server and rebuilding the bundle every time you make a code change is kinda boring, we need something better. Using Webpack’s dev middleware we can automatically update the bundle on code changes. The bundle is served from memory and rebuilds are much faster. And it gets even better, using Webpack’s hot middleware together with React Hot Loader we can apply the updates to a running React app, no need for a page refresh. It is awesome! Hot reloading on the server is done by plugging into the Webpack compiler and trashing the require cache when Webpack detects changes in the app source.

CSS Modules, Sass and Autoprefixer with CSS hot loading

This is a little bit tricky to set up, but bear with me. The goal is to have Sass, CSS Modules and Autoprefixer working together with server-side rendering, Webpack, hot loading, sourcemaps and of course linting.

Most of the work is already done by adding some additional loaders to Webpack. Webpack knows how to import (or require) an asset other than JavaScript as it passes it trough a series of loaders specified in the config file. Webpack makes those imports work for the client, but for the server we need something else. This is where webpack-isomorphic-tools come in handy. This module keeps track of what is generated by Webpack (and its loaders) and makes importing these assets work on the server as well.

Setting up webpack-isomorphic-tools is not trivial, but it’s worth it.

Production strategy using hashes for cache invalidation

In production we want to get rid of the overhead of transpiling by pre-building server and client code. We also want hashed assets to make use of far-future caching. These asserts can be deployed to a CDN, by changing the publicPath in webpack.config.js to point to the CDN the paths are updated automatically.

Routing with React Router

While not your only choice, React Router definitely is the most popular choice when it comes to routing. It supports server-side routing and it supports browser History API on the client.

What React Router doesn’t solve out of the box is handling of meta data like title or status. For title (and other <head> related meta data) there is React Helmet and for HTTP status when rendering on the server we use a small helper utility. Both are used React component’s render functions to support dynamically changing them, for example when a blog article is not found.

Managing application state with Redux

Sooner or later you might need some more advanced state management than React gives you with component state. Redux is a good choice. Since we’re building a blog here it makes sense to keep loaded articles in this state. Redux features a store, reducers and actions, which are often grouped together. For this boilerplate I want to try a different approach and instead of grouping by nature we will group by domain. If you want to know more about this approach I encourage you to read “Rules For Structuring (Redux) Applications” and “A Better File Structure For React/Redux Applications”.