react-engine

What is react-engine?
- a react render engine for Universal (previously Isomorphic) JavaScript apps written with express
- renders both plain react views and optionally react-router views
- enables server rendered views to be client mountable
Install
$ npm install react-engine react react-dom react-router --save
Usage On Server Side
Setup in an Express app
var Express = require('express');
var ReactEngine = require('react-engine');
var app = Express();
var engine = ReactEngine.server.create({
});
app.engine('.jsx', engine);
app.set('views', __dirname + '/views');
app.set('view engine', 'jsx');
app.set('view', require('react-engine/lib/expressView'));
Setup in a KrakenJS app's config.json
{
"express": {
"view engine": "jsx",
"view": "require:react-engine/lib/expressView",
},
"view engines": {
"jsx": {
"module": "react-engine/lib/server",
"renderer": {
"method": "create",
"arguments": [{
}]
}
}
}
}
Server options spec
Pass in a JavaScript object as options to the react-engine's server engine create method.
The options object should contain the mandatory routes property with the route definition.
Additionally, it can contain the following optional properties,
-
docType: <String> - a string that can be used as a doctype (Default: <!DOCTYPE html>).
(docType might not make sense if you are rendering partials/sub page components, in that case you can pass an empty string as docType)
-
routesFilePath: <String> - path for the file that contains the react router routes.
react-engine uses this behind the scenes to reload the routes file in
cases where express's app property view cache is false, this way you don't need to restart the server every time a change is made in the view files or routes file.
-
renderOptionsKeysToFilter: <Array> - an array of keys that need to be filtered out from the data object that gets fed into the react component for rendering. more info
-
performanceCollector: <Function> - to collects perf stats
-
scriptLocation: <String> - where in the HTML you want the client data (i.e. <script>var __REACT_ENGINE__ = ... </script>) to be appended (Default: body).
If the value is undefined or set to body the script is placed before the </body> tag.
The only other value is head which appends the script before the </head> tag.
-
staticMarkup: <Boolean> - a boolean that indicates if render components without React data attributes and client data. (Default: false). This is useful if you want to render simple static page, as stripping away the extra React attributes and client data can save lots of bytes.
-
scriptType: <String> - a string that can be used as the type for the script (if it is included, which is only if staticMarkup is false). (Default: application/json).
Rendering views on server side
var data = {};
res.render(viewName, data);
res.render(req.url, data);
Usage On Client Side (Mounting)
var client = require('react-engine/lib/client');
document.addEventListener('DOMContentLoaded', function onLoad() {
client.boot(, function onBoot(data, history) {
});
};
var data = client.data();
Client options spec
Pass in a JavaScript object as options to the react-engine's client boot function.
It can contain the following properties,
routes : required - Object - the route definition file.
viewResolver : required - Function - a function that react-engine needs to resolve the view file.
an example of the viewResolver can be found here.
mountNode : optional - HTMLDOMNode - supply a HTML DOM Node to mount the server rendered component in the case of partial/non-full page rendering.
history : optional - Object - supply any custom history object to be used by the react-router.
Data for component rendering
The actual data that gets fed into the component for rendering is the renderOptions object that express generates.
If you don't want to pass all that data, you can pass in an array of object keys or dot-lookup paths that react-engine can filter out from the renderOptions object before passing it into the component for rendering.
var engine = ReactEngine.server.create({
renderOptionsKeysToFilter: [
'mySensitiveData',
'somearrayAtIndex[3].deeply.nested'
],
routes: require(path.join(__dirname + './reactRoutes'))
});
Notes:
- The strings
renderOptionsKeysToFilter will be used with lodash.unset, so they can be either plain object keys for first-level properties of renderOptions, or dot-separated "lookup paths" as shown in the lodash.unset documentation. Use these lookup paths to filter out nested sub-properties.
- By default, the following three keys are always filtered out from
renderOptions no matter whether renderOptionsKeysToFilter is configured or not.
settings
enrouten
_locals
Handling redirects and route not found errors on the server side
While using react-router, it matches the url to a component based on the app's defined routes. react-engine captures the redirects and not-found cases that are encountered while trying to run the react-router's match function on the server side.
To handle the above during the lifecycle of a request, add an error type check in your express error middleware. The following are the three types of error that get thrown by react-engine:
| MATCH_REDIRECT** | indicates that the url matched to a redirection |
| MATCH_NOT_FOUND | indicates that the url did not match to any component |
| MATCH_INTERNAL_ERROR | indicates that react-router encountered an internal error |
** for MATCH_REDIRECT error, redirectLocation property of the err has the new redirection location
app.use(function(err, req, res, next) {
console.error(err);
if (res.headersSent) {
return next(err);
}
if (err._type && err._type === ReactEngine.reactRouterServerErrors.MATCH_REDIRECT) {
return res.redirect(302, err.redirectLocation);
}
else if (err._type && err._type === ReactEngine.reactRouterServerErrors.MATCH_NOT_FOUND) {
return res.status(404).send('Route Not Found!');
}
else {
return res.status(500).send(err.message);
}
});
Yeoman Generator
There is a Yeoman generator available to create a new express or KrakenJS application which uses react-engine:
generator-react-engine.
Performance Profiling
Pass in a function to the performanceCollector property to collect the stats
object for every render.
stats
The object that contains the stats info for each render by react-engine.
It has the below properties.
name - Name of the template or the url in case of react router rendering.
startTime - The start time of render.
endTime - The completion time of render.
duration - The duration taken to render (in milliseconds).
function collector(stats) {
console.log(stats);
}
var engine = require('react-engine').server.create({
routes: './routes.jsx'
performanceCollector: collector
});
Notes
- On the client side, the state is exposed in a script tag whose id is
react-engine-props
- When Express's
view cache app property is false (mostly in non-production environments), views are automatically reloaded before render. So there is no need to restart the server for seeing the changes.
- You can use
js as the engine if you decide not to write your react views in jsx.
- Blog on react-engine
- You can add nonce in
_locals, which will be added in script tag that gets injected into the server rendered pages, like res.locals.nonce = 'nonce value'
License
Apache Software License v2.0