This project is no longer under development and is outdated. If you are looking to start a new React project, consider using Create React App.
A React and Node with ES6 demo project that serves as a showcase for a great toolchain for building single page applications backed by a JSON API. It is meant to showcase a set of technologies that can not only result in robust web applications, but also facilitate rapid development and ease of developer onboarding. It can also serve as seed for starting new projects.
- Clone the repo
$ npm install
- Source files for the front end are located in the ./src directory.
- Run the
$ gulp build
task to build the client-side app into the./build
directory. * If you get an errorCannot find module ...v8flags/cache/4.1.0.12.flags.json
, try force fetching updated v8 flags for Gulp by running$ node path/to/your/global/install/gulp/node_modules/v8flags/fetch.js
.
Run the default $ gulp
task to:
- Run the tests
- Build from
./src
into./build
via webpack - start the Node server
- start the webpack development server to server client-side assets
- Watch for changes. All changes will to JS/JSX will re-run the tests. Changes to source JS/CSS/Markup will trigger a re-build.
For viewing in the browser, you can navigate to http://localhost:3000/webpack-dev-server/#/
to view the app in live-reload mode, or http://localhost:8080/
for standard (refresh to see changes) mode.
A production-ready, minified build can be created in the ./build
directory by running $ gulp build:production
.
When deploying to a hosting service (such as Heroku), make sure to set NODE_ENV=production
and MONGO_URI
to your MongoDB instance URI in your environment variables.
A Heroku deployment of this example app can be viewed here.
The webpack module bundler is the principal build tool, and supports our component-based architecture very well. Webpack's myriad features and advantages as a module bundler are too many to list here. However, a key feature to this project is that stylesheets are 'required' within component source code in the same CommonJS format as JavaScript dependencies, e.g., require('./stylesheet.css')
.
Gulp is used to fill in the gaps around webpack and automate groups of tasks with a single command, e.g. starting the backend server and the development server simultaneously.
Gulp's straightforward syntax makes configuration of tasks both quick to setup and easy for other developers to interpret and build upon. It's use of "pipes" and streaming data not only makes it fast but also makes it easy to reason about the flow of data through the build process.
Gulp tasks can be found in the ./gulp/tasks
directory, and configuration is consolidated in a single ./gulp/config.js
file.
For many if not most client-side single-page applications, what's needed most from the server-side is a JSON API. Node and Express offer the fastest and easiest route to getting a RESTful API up and running with little overhead, while leaving lots of room for expansion should more complex services be necessary.
Mongo's document-based storage and flexible schemas offer a fast route to persisting data without the need for much configuration, while offering the potential of scalability. This makes is a great complement to Node and Express for building simple backends to facilitate rapid prototyping of client-side apps. This could easily swapped out for a relational database like Postgres if preferred.
React allows us to ditch the age-old MVC architecture for a more component-based approached. Component-based development allows for a front end that is highly reusable and extendable, with both data flows and interaction flows that are easy to follow and reason about. React offers the best tool for building view-layer components currently available. It uses JavaScript constructs that will already be familiar to most developers, and its virtual DOM-based rendering is super fast. It also opens up the possibility of server-side rendering of view as well.
The architecture of this app applies the principles of Atomic Design to React components. Components are organized into atoms, molecules, organisms, templates, and pages. The stylesheets and tests for the component along with the JavasScript/JSX in the same directory. Stylesheets adhere to the same rules as they would under a normal Atomic CSS layout. However, with the exception of a few global styles, every style and stylesheet must belong to a component. Global style rules can be passed to a component by importing common.less
into the component's local stylesheet. This pattern is very handy for organizing complex groups of components, and makes mentally mapping the location of code, tests, or styles related to a particular component or structure within the app very intuitive.
Routing is performed via React Router.
Flux is Facebook's recommended approach to managing the flow of data in a React component-based application. I found Flux's unidirectional data flow to be very intuitive, making reasoning about state and the flow of data relatively straightforward. While Flux is more of design pattern than a formal framework, the implementation here is based fairly directly on the implementation described in the official Flux docs. By managing application state in stores and keeping most business logic out of view components, most aspects of the application are able to remain highly decoupled.
Stylesheets are written with Less. If you prefer Sass, the the project can be converted by swapping the webpack less-loader for sass-loader. However, node-sass currently has issues supporting Node v0.12 and io.js which require it to be rebuilt from the latest source rather than installed via npm. Sass support can also be achieved by using Node v0.10.* instead.
Server-side testing is done with Mocha and Supertest. Client side testing is also done with Mocha via the Karma test runner. The full test suite can be run with $ gulp test
. Client-side only tests can be run with $ gulp test:client
and server-side only with gulp test:server
. All files ending in -spec.js
or -spec.jsx
in the ./src
and ./server
directories will be detected, bundled, and run automatically by the test runners.
A good explanation can be found here.
Given the current shortcomings of Jest, it's my opinion that this recipe represents the best option for testing React apps. The Karma test runner is blazing fast, allows for running tests in both a headless environment via PhantomJS and in the browser, and couples well with the webpack module bundler for bundling test code and converting JSX. I prefer Mocha and Chai, but Jasmine could easily be substituted as well.
Since we don't have the benefit of Jest's automocking with this setup, we'll have to handle mocking on our own. Thankfully Sinon and Rewire make this easy. A simple helper module facilitates mocking and testing of calls to external dependencies with Sinon or replacing child React components with dummy ones possible with very little code (example here).
- Server-side rendering of React components