Code Monkey home page Code Monkey logo

react-engine's Introduction

react-engine

Build Status

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

# In your express app, react-engine needs to be installed alongside react/react-dom (react-router is optional)
$ 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();

// create an engine instance
var engine = ReactEngine.server.create({
  /*
    see the complete server options spec here:
    https://github.com/paypal/react-engine#server-options-spec
  */
});

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

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

// set jsx or js as the view engine
// (without this you would need to supply the extension to res.render())
// ex: res.render('index.jsx') instead of just res.render('index').
app.set('view engine', 'jsx');

// finally, set the custom view
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": [{
          /*
            see the complete server options spec here:
            https://github.com/paypal/react-engine#server-options-spec
          */
        }]
      }
    }
  }
}
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 = {}; // your data model

// for a simple react view rendering
res.render(viewName, data);

// for react-router rendering
// pass in the `url` and react-engine
// will run the react-router behind the scenes.
res.render(req.url, data);

Usage On Client Side (Mounting)

// assuming we use a module bundler like `webpack` or `browserify`
var client = require('react-engine/lib/client');

// finally, boot whenever your app is ready
// example:
document.addEventListener('DOMContentLoaded', function onLoad() {

  // `onBoot` - Function (optional)
  // returns data that was used
  // during rendering as the first argument
  // the second argument is the `history` object that was created behind the scenes
  // (only available while using react-router)
  client.boot(/* client options object */, function onBoot(data, history) {

  });
};

// if the data is needed before booting on
// client, call `data` function anytime to get it.
// example:
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.

// example of using `renderOptionsKeysToFilter` to filter `renderOptions` keys
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:

Error Type Description
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

// example express error middleware
app.use(function(err, req, res, next) {
  console.error(err);

  // http://expressjs.com/en/guide/error-handling.html
  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 {
    // for ReactEngine.reactRouterServerErrors.MATCH_INTERNAL_ERROR or
    // any other error we just send the error message back
    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).
// example
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

react-engine's People

Contributors

7aos avatar benox3 avatar cerebrl avatar chunkiat82 avatar duaneobrien avatar gabrielcsapo avatar gocreating avatar grawk avatar hosmelq avatar internetsadboy avatar jintoppy avatar jonathansamines avatar joshuabaker2 avatar jugend avatar kumarrishav avatar masotime avatar pazguille avatar perumalcsbe avatar rayho-hw-dev avatar reggi avatar remarkablemark avatar samsel avatar samuelcouch avatar simongong avatar skarflacka avatar stevemao avatar svenheden avatar toksea avatar vuhwang avatar wangzuo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

react-engine's Issues

Breaking the encapsulation of Client

I have noticed the following line in index.js the examples:

var Client = require('react-engine/lib/client');

When I saw this, I thought that it is bad form because it makes assumption about internals of react-engine. I 'fixed' it like this:

var Client = require('react-engine').client;

However, this didn't work for browserify - I got weird errors about 'not being able to find react module' in the browser console.

I still think that we should not reach into 'lib' folders of react-engine, but somehow this works for me, albeit leaving me with mixed feelings :-).

Use webpack instead of browserify and add settings to support ES6 style

As this is at initial stage, it would be great to add support for ES6 now itself. And, webpack also support to add a middleware at server side to generate the bundle files fast(by generating bundles in the memory itself without creating physical files) which helps while in development, and also has a great ES6 support

Question about client-side/server-side rendering for clarity

So i setup react-engine as the view engine with krakenjs and everything has been working fine. My app.js file that bootstraps the client-side looks like the example below and i simply have a folder structure where views contains my server-side rendered pages like index, header, footer, single-listing and views also contains a directory called components which are bundled with browserify... so the problem i just noticed is the server-side and client-side files are being added into my bundle.js file. This was noticeable recently when i tried to do an $.ajax call inside components/AccountActions.jsx which i thought was only client-side.. and i received the error $ is not available or window is not available. I was wondering a few things.

  1. what is the purpose of the require('./views/**/*.jsx', {glob: true});
  2. does viewResolver handle paths for client-side views, server-side views or both?
  3. what is a good way to ensure that my components directory stays client-side and the rest within views is server-side. If it's only client-side where is the path located for server-side views?

If you need any more information feel free to ask :) Thanks!

app.js

'use strict';

var Client = require('react-engine/lib/client');

require('./views/**/*.jsx', {glob: true});

var options = {
  viewResolver: function(viewName) {
    return require('./views/' + viewName);
  }
}

document.addEventListener('DOMContentLoaded', function onLoad() {
  Client.boot(options);
})

Using React Router Link

I have added a Navigation component within layout.jsx. Currently I have to use anchor tags, rather than React Routers Link component, which would be preferred. When I require the Link component within the render function of the Navigation component I can use Link and it seems to work on the front end, but I get the following error in the console:

Warning: Failed Context Types: Required context 'router' was not specified in 'Link'. Check the render method of 'Nav'.
TypeError: Cannot read property 'makeHref' of undefined

And here is the content of the render function of Nav.

var Link = require('react-router').Link;
            return (
                <nav className="background-first main-nav">
                    <section className="nav-wrap">
                        <section className="main-nav-left">
                            <div className="main-nav-logo"><Logo /></div>
                            <div className="plus-icon" onClick={mobileMenuShow}>+</div>
                        </section>
                        <section className="main-nav-right">
                            <ul ref="navList" className="main-nav-list">
                                <Link to="signup">Signup</Link>
                                <li><a href="/signup">Sign Up</a></li>
                                <li><a href="#">Log In</a></li>
                                <li><a href="#">Quick Start</a></li>
                                <li><a href="#">Docs</a></li>
                                <li><a href="#">About</a></li>
                            </ul>
                        </section>
                    </section>
                </nav>

Is this because the layout component is coming from the server and our router is not available at that time? But why then if I include Link = require('react-router').Link within the render function of Nav does it work after its rendered to the client?

Is there a known way to make Link work in the layout component? Because it seems like that is the most logical place for a navigation.

Client-side Booting w/out Browserify

I'm currently using webpack to do my client-side bundling. However, when I try to require('react-engine').client, I get the following build errors:

WARNING in ./~/react-engine/lib/server.js
Critical dependencies:
73:15-49 the request of a dependency is an expression
106:19-33 the request of a dependency is an expression
 @ ./~/react-engine/lib/server.js 73:15-49 106:19-33

WARNING in ./~/react-engine/lib/util.js
Critical dependencies:
55:13-26 the request of a dependency is an expression
 @ ./~/react-engine/lib/util.js 55:13-26

ERROR in ./~/react-engine/package.json
Module parse failed: [redacted]/node_modules/react-engine/package.json Line 2: Unexpected token :
You may need an appropriate loader to handle this file type.
| {
|   "name": "react-engine",
|   "version": "1.6.0",
|   "description": "a composite render engine for express apps to render both plain react views and react-router views",
 @ ./~/react-engine/lib/expressView.js 21:29-50

ERROR in ./~/react-engine/lib/config.json
Module parse failed: [redacted]/node_modules/react-engine/lib/config.json Line 2: Unexpected token :
You may need an appropriate loader to handle this file type.
| {
|   "docType": "<!DOCTYPE html>",
|   "client": {
|     "markupId": "react-engine-props",
 @ ./~/react-engine/lib/server.js 20:13-32

ERROR in ./~/react-engine/~/glob/glob.js
Module not found: Error: Cannot resolve module 'fs' in [redacted]/node_modules/react-engine/node_modules/glob
 @ ./~/react-engine/~/glob/glob.js 43:9-22

ERROR in ./~/react-engine/~/glob/sync.js
Module not found: Error: Cannot resolve module 'fs' in [redacted]/node_modules/react-engine/node_modules/glob
 @ ./~/react-engine/~/glob/sync.js 4:9-22

I'm just making a guess at this point, but when I see attempts to require the fs module in a client-side script, I have to assume browserify is implied?

On a separate (but related) topic, looking at everything that would have been brought in via require('react-engine') in the first place, it looks like that's a rather bloated payload just for the sake of hooking up React once on the client. Is there a leaner approach that I'm missing?

Adding more than 1 route

I followed the complex example and managed to get the expected output however when I try to add more routes in the routes.jsx file

var routes = (
    <Router.Route handler={App}>
        <Router.DefaultRoute name='home' handler={Home} />
        <Router.Route name='login' handler={Login} />
    </Router.Route>
);
module.exports = routes;

when I try to load the page localhost:8080/login i get the following error.

Uncaught Error: Invariant Violation: You're trying to render a component to the document using server rendering but the checksum was invalid. This usually means you rendered a different component type or props on the client from the one on the server, or your render() methods are impure. React cannot handle this case due to cross-browser quirks by rendering at the document root. You should look for environment dependent code in your components and ensure the props are the same client and server side:

Could anyone guide me in to fixing this problem?

Example of how to integrate with flux style stores.

React Engine looks like a great solution to the sort of isomorphic apps I'm building. In all of the examples the data is passed down though props. How would a controller view get its own data in this setup?

Complex Example throwing errors

Got these errors when trying out the complex example provided. Any help would be appreciated.

Error: asking to use react router for rendering, but no routes are provided
    at ReactEngineView.render (/Users/user_punks/workspace/react-engine/examples/complex/node_modules/react-engine/lib/server.js:92:19)
    at ReactEngineView.render (/Users/user_punks/workspace/react-engine/examples/complex/node_modules/react-engine/lib/expressView.js:51:10)
    at tryRender (/Users/user_punks/workspace/react-engine/examples/complex/node_modules/express/lib/application.js:639:10)
    at EventEmitter.render (/Users/user_punks/workspace/react-engine/examples/complex/node_modules/express/lib/application.js:591:3)
    at ServerResponse.render (/Users/user_punks/workspace/react-engine/examples/complex/node_modules/express/lib/response.js:961:7)
    at app.use.res.render.title (/Users/user_punks/workspace/react-engine/examples/complex/index.js:49:7)
    at Layer.handle [as handle_request] (/Users/user_punks/workspace/react-engine/examples/complex/node_modules/express/lib/router/layer.js:95:5)
    at next (/Users/user_punks/workspace/react-engine/examples/complex/node_modules/express/lib/router/route.js:131:13)
    at Route.dispatch (/Users/user_punks/workspace/react-engine/examples/complex/node_modules/express/lib/router/route.js:112:3)
    at Layer.handle [as handle_request] (/Users/user_punks/workspace/react-engine/examples/complex/node_modules/express/lib/router/layer.js:95:5)

What the `viewResolver` actually is?

1. The path problem

I use console.log() to print the parameter viewName and find that it is an absolute path in my project but a relative path in react-engine example.

That's really really really unreasonable.....

2. Few document for the purpose of this function

The only docs on this function is in README page:

supply a function that can be called to resolve the file that was rendered

so who will call this function?
when it would be called?
and what is the parameter viewName mean?

This function does matter!!!
The whole view engine won't work correctly without correct viewResolver but there is only one line of explanation

Export Router object to consumers

We have a scenario where we want to programatically transition between routes on the client. Easiest way to achieve this is to use the Router#transitionTo API provided by react-router, but the problem is that react-engine abstracts away the router creation and we have no direct access to the created router object.

Can the router object be passed to the callback provided to Client.boot()?

Webpack support

Hello everyone! How can I use react-engine with webpack and him a system of plugins instead of browserify? I tried, but I got many errors.

Module not found: Error when running webpack

I am getting this error when starting the server (I am using webpack):

ERROR in ./~/react-engine/lib/client.js
Module not found: Error: Cannot resolve 'file' or 'directory' ./config in     C:\address\toapp\node_modules\react-engine
 \lib
 @ ./~/react-engine/lib/client.js 18:13-32

How to prime Flux stores

For a full Flux architecture, we would need to have a dispatcher and one or more stores on the client that views listen to. When rendering a page on the server, we transfer view state to the client and mount the views, but I don't see how to also initialize and transfer stores so that they have the correct state when client is bootstrapped.

If render url contains period "Error: Cannot find module"

When your using express the docs use res.render(req.url, data) the following to render the url to react. This is causing an issue anytime there is a period in the url.

I have periods in my get parameters and in my route. You can pass req.path to pass only the path to the router. There is also periods in the url like /index.html the error is Error: Cannot find module 'html'.

Do I have to escape periods to the url? res.render(req.url.replace(/\./g, ""), data)

Unable to integrate with Kraken

I am trying to start a kraken project with react-engine, and after everything is set up. I got this error...

ReferenceError: marge is not defined
    at /Users/lhsieh/Documents/PayPal/code/sandbox-dashboard/node_modules/kraken-js/node_modules/confit/lib/common.js:45:32

There is my config file in kraken

{

  "express": {
    "view engine": "jsx",
    "view": "require:react-engine/lib/expressView",
    "views": "path:./public/views"
  },

  "i18n": {
    "contentPath": "path:./locales",
    "fallback": "en-US"
  },

  "view engines": {
    "jsx": {
      "module": "react-engine/lib/server",
      "renderer": {
        "arguments": [{
          "cache": false
        }, {
          "views": "config:express.views",
          "view engine": "config:express.view engine",
          "i18n": "config:i18n"
        }]
      }
    }
  },

  "middleware": {
    "router": {
      "module": {
        "arguments": [{
          "directory": "path:./controllers"
          }]
      }
    }
  }

}

did not know what is wrong with it, any example of using react-engine in kraken ? Thanks.

Difference between examples and readme

The readme.md is set up to use views instead of public/views and it seems like it adds some updated functionality, how are layouts and routes handled in this case?

The examples show the old functionality that I'm familiar with, using /public/views.

I'd love an explication / updated examples showing how to use the readme version.

Trouble setting up react-engine with krakenjs

I recently came across the article here about creating an isomorphic react application and was greatly interested in playing around with this idea. I started following the config for setting this up and added the following

  {
    "express": {
        "view engine": "jsx",
        "view": "require:react-engine/lib/expressView",
    },
    "view engines": {
        "jsx": {
            "module": "react-engine/lib/server",
            "renderer": {
              "method": "create",
                "arguments": [{
                    "reactRoutes": "path:<PATH_TO_REACT-ROUTER_ROUTES>",
                    "performanceCollector": "require:<PATH_TO_PERF_COLLECTOR_FUNCTION>"
                }]
            }
        }
    }
  }

After including that in my config.json and installing react-engine via npm i --save react-engine i'm getting the following error after running npm start. Wondering if there is anything i'm missing? Thanks!

Improving server side error handling

In a case of an error on the server side, the next middleware in chain is called without logging the error. In some cases the rendering logic silently fails and it's hard to debug rendering issues. An example would be rendering a template from an existing error middleware.

Suggested improvement: Adding a debug statement in the catch block.

After following the configuration and setup process it is unclear how to add new routes/views

I tried adding new routes but they are still being intercepted by express default routing. Perhaps, you have answered my issue in your post Isomorphic React Apps with React-Engine where you say:

"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."

However, I believe, you did not specify this in the readme nor the examples. Furthermore, it would be nice to explain how we can add more routes. People like me that are just starting to learn react won't find it easy.

Note: I did follow the examples at react-router but for some reason the only way to make it work was using express routing and I dont think this was the way it was meant to work or am I getting everything wrong?

Thank you!

EDIT:

This is what I am doing to add new routes (with react-router) and views (.jsx thanks to react-engine), please correct me if I am wrong:

If we want to add a new view, lets say users.jsx and route it to path: /users

  • Add the following code to the express engine index.js file (in the case of your examples, it could be called server.js):
app.get('/users', function(req, res) {
  res.render(req.url, {
    title: 'Users page',
    name: 'Frank'
  });
});
  • Then, add the route to the routes.jsx file as follows:
 <Route path='/' handler={App}>
     <Router.DefaultRoute name='index' handler={Index} />
     <Route name='users' path='/users' handler={Users} />
 </Route>

Is this correct?
Is there a way to avoid having to add app.get('/users'.......){}?

Update notes from 1.7.0 to 2.0.0 version?

I just updated to version 2.0.0 from 1.7.0 and I am having a difficult time updating my code. Can you please provide an update guide.

I am getting the following error:
Error: asking to use react router for rendering, but no routes are provided

I am providing my routes as follows:

var engine = ReactEngine.server.create({
  routesFilePath: path.join(__dirname + '/routes')
});

EDIT:
ok, I didnt check the example files, the solution was there. So, I would recommend to update the readme and specify that we first need to require the routes file. The final code looks like this:

var engine = ReactEngine.server.create({
  routes: require(path.join(__dirname + '/routes')),
  routesFilePath: path.join(__dirname + '/routes')
});

Cannot set custom scroll behavior function

We're developing an app which requires us to have fine-grain control over the browser scroll behaviour on transition.

With react-router, we're able to provide a custom function to control the scroll behaviour when the Router is created via 'scrollBehavior' property:

eg:

Router.create({
    scrollBehavior: function (position, actionType) {
     // Scroll here
    })
}

react-engine abstracts the Router creation from consumers, and we're not able to override the default behaviour (ImitateBrowserBehavior)

Futher, react-engine uses Router.run() to create the router (in react-engine/lib/client.js) which, according to the documentation, cannot be used to completely customize the router. From react-router/lib/runRouter.js:

If you need to specify further options for your router such as error/abort handling or custom scroll behavior, use Router.create instead."

Can you expose router configuration via API in react-engine?

resolve cache clear logic based on the 'view cache'

Summary of the request

We have been using it for our new application and we have found one issue. We don't want to cache React views in our 'mock' environment (we don't use the 'development' env that much).

You have there a check for the 'development' environment, but as I mentioned, we are using the 'mock' env.

Can you please resolve your cleaning logic based on the 'view cache' (true | false) parameter from config files instead of doing it only for the 'development' env?

Allow finer grain control of render properties

When rendering on the server, react-engine constructs a object containing data for rendering based on "a mash of express render options, res.locals and meta info about react-engine" (quoted from the documentation in react-engine/lib/server.js). This is not ideal in all scenarios because this data is also sent to the client (via REACT_ENGINE variable) when there is no need.

We've specifically hit two scenarios:

  1. We are using third party middleware which attaches content to res.locals. That content is completely unnecessary for rendering. react-engine blindly copies this data and includes it for rendering on both server and client side. This is wasteful (increases the overall payload) and also leads to potential security issues.
  2. On the server, we fetch a HTML snippet and provide it as part of the render
var renderObj = {
    "top": encodeUriComponent("<div class='top'>My top section<div>")
};
res.render("template", renderObj);

Within our template, we then insert the raw HTML using the dangerouslySetInnerHTML API in React:

<div dangerouslySetInnerHTML={{__html: decodeURIComponent(this.props.top)}} />

This is a situation were we do want the content to be supplied during server side rendering, but it should not be sent as part of the payload to the client.

Handling errors with express when wildcard

This is an example of react router handling errors with react.

var React = require('react')
var Router = require('react-router')

var App = require('./views/app.jsx')
var Error = require('./views/error.jsx')
var Account = require('./views/account.jsx')

module.exports = (
  <Router.Route path='/' handler={App}>
    <Router.DefaultRoute name='account' handler={Account} />
    <Router.NotFoundRoute handler={Error} />
  </Router.Route>
)

If an express route is given a wildcard and react-engine is rendering the url, as in the following example, if react-engine can't fine a route the 404 is served by react, and the express error handler below will never fire.

app.get('*', function (req, res) {
  return res.render(req.url, {
    title: 'React Engine Express Sample App',
    name: 'Thomas'
  })
})

app.use(function (req, res, next) {
  var err = new Error('Not Found')
  err.status = 404
  return next(err)
})

app.use(function (err, req, res) {
  return res.render('error', {
    title: err.status + ' Error',
    url: req.url
  })
})

Is there a way for react-engine to be smart enough to detect when a route is missing and pass next to res.render allowing for the express error handler to run?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.