react: Server rendering is slower with npm react

I ran a few benchmarks on the server (modifying https://github.com/paulshen/react-bench to not use jsdom). The results were surprising, as the browserified react.js was about 30% faster than the npm version, even with NODE_ENV=production.

The performance ranking (test run time) was react.min.js < react.js < NODE_ENV=production node react < node react.

I suspect process.env is not a regular js object but perhaps a getter and thus carries a penalty when you test for "production" !== process.env.NODE_ENV everywhere.

Also the minified version might still perform best of all, as at least some time ago V8 used function source length (including comments) as a heuristic for function complexity / compilation time and thus affecting chances for optimization in some cases, but the effect might be negligible.

About this issue

  • Original URL
  • State: closed
  • Created 10 years ago
  • Reactions: 10
  • Comments: 59 (24 by maintainers)

Commits related to this issue

Most upvoted comments

@mhart Technically you can fix the problem in your own code by doing process.env = JSON.parse(JSON.stringify(process.env)), converting it from a live object that calls getenv down a plain JS object. You’ll get the same performance benefits, with the only downside that any code that was relying on live edits to the env (does anyone really do that?) will fail.

Referencing https://github.com/facebook/fbjs/pull/86 which will fix this now that UglifyJS can properly eliminate dev code (even if it references a var that never changes) with its new reduce_vars option, which is a default.

See https://github.com/facebook/fbjs/pull/86#issuecomment-285204734 for more context.

Lately I have been simply using a wrapped module

var React;
if (process.env.NODE_ENV !== 'production') {
  React = require('./react-with-addons-0.10.0.js');
} else {
  React = require('./react-with-addons-0.10.0.min.js');
}
module.exports = React;

Works great. You could consider switching npm package to some such scheme if there are no downsides.

@STRML thanks! However, I’ve seen a warning that babel/register is not suitable for libraries. I’ve only used babel/register on files in my app. I’m curious if people use it on node modules commonly in production.

If you’re already using babel on your server-side code (say, via babel-node or require('babel-register')), you can add the inline env transformer to get around this problem.

Call me all crazy, just had a left field idea. Could the transformer that builds the npm module create 2 complete copies of react? one for dev and one for production?

In the the normal version of react var React = require('react') could you there look at the NODE_ENV and swap which module is returned? This way on server you only get the performance hit once;

I’m using webpack and new webpack.DefinePlugin({'process.env.NODE_ENV': '"production"'}) was enough to solve it for me. Is there no such thing in browserify?