Universal React + Redux Boilerplate
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?
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!
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:
- Universal or isomorphic. However you’re calling it... “Server-side rendering is not a fallback; client-side rendering is an enhancement” (source).
- React for obvious reasons, React Router to deal with routing and React Helmet to manage changes in the document head.
- Hot Module Replacement using React Hot Loader 3.
- Redux to keep application state predictable and Redux DevTools to help with debugging.
- Server using Koa, the next generation web framework developed by the team behind Express.
- Babel so we can use the latest ECMAScript additions and even the ones that have not made it to the standard yet, use with caution.
- Client bundle created by Webpack 2, which includes tree-shaking.
- Mocha and Enzyme to run your tests so your app (and you) stay healthy.
- It’s your code style, but ESLint helps keep it consistent.
- Static type checking using Flow can help you find errors quickly.
- Development and production build processes
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
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
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.
.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.
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.
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
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”.