Isomorphic React Apps with React-Engine

By

Earlier this year, we started using react in our various apps at PayPal. For existing apps the plans were to bring react in incrementally for new features and start migrating portions of the existing functionality into a pure react solve. Regardless, most implementations were purely client side driven. But most recently, in one of the apps that we had to start from scratch, we decided to take a step forward and use react end to end. Given express based kraken-js as PayPal’s application stack, we wanted to incorporate react Views in JS or JSX to be the default template solution along with routing and isomorphic support.

Thus, a summary of our app’s requirements were

  1. Use react’s JSX (or react’s JS) as the default template engine in our kraken-js stack
  2. Support server side rendering and preserve render state in the browser for fast page initialization
  3. Map app’s visual state in the browser to URLs using react-router to support bookmarking
  4. Finally, support both react-router based UI workflows and simple stand alone react view UI workflows in kraken-js

As we started working towards the above requirements, we realized that there was a lot of boiler plate involved in using react-router along side with simple react views in an express app. react-router requires its own route declaration to be run before a component can be rendered, because it needs to figure out the component based on URL dynamically. But plain react views could be just rendered without any of those intermediate steps.

We wanted to take this boiler plate that happens at the express render time and simplify it using a clean api. Naturally, all things pointed to express’s `res.render`. The question became very clear now on how `res.render` can be used as-is without any api facade changes but support both react-router rendering and regular react view rendering.

Thus react-engine was born to abstract all of the complexities into the res.render!

So in simple terms, react-engine is a Javascript library for express based NodeJS web apps for rendering composite react views. The phrase composite react views reflects react-engine’s ability to handle rendering of both react-router based UI workflows and stand alone react views.

Render Example
// to run and render a react router based component
res.render('/account', {});
// or more generically
res.render(req.url, {});

// to render a react view
res.render('index', {});

Notice how the first render method is called with a `/` prefix in the view name. That is key to the react-engine’s MAGIC. Behind the scenes, react-engine uses a custom express View to intercept view names and if they start with a `/` then it first runs the react-router and then renders the component that react router spits out or if there is no `/` then it just renders the view file.

Setup Example
var express = require('express');
var engine = require(‘react-engine');

var app = express();

// react-engine options
var engineOptions = {
  // optional, if not using react-router
  reactRoutes: 'PATH_TO_REACT_ROUTER_ROUTE_DECLARATION' 
};

// set `react-engine` as the view engine
app.engine('.jsx', engine.server.create(engineOptions));

// set the view directory
app.set('views', __dirname + '/public/views');

// set js as the view engine
app.set('view engine', 'jsx');

// finally, set the custom react-engine view for express
app.set('view', engine.expressView);

In a nutshell, the code sets react-engine as the render engine with its custom express View for express to render jsx views.

react-engine supports isomorphic react apps by bootstrapping server rendered components onto the client or browser in an easy fashion. It exposes a client api function that can be called whenever the DOM is ready to bootstrap the app.

document.addEventListener('DOMContentLoaded', function onLoad() {
    client.boot(options, function onBoot(renderData) {
    });
});
The complete options spec can be found here. More detailed examples of using react-engine can be found here https://github.com/paypal/react-engine/tree/master/examples.

We love react at PayPal and react-engine helps us abstract out the boiler plate in setting up react to be used with react-router in isomorphic express apps and focus on writing the business logic.

Sam Selvanathan

I am a software engineer with passion for developing mobile and web apps. Apart from my regular day work at PayPal, I like to explore/hack on emerging libraries and technologies. Currently a big fan of Node!