Hastening React SSR with component memoization and templatization

Hastening React SSR with component memoization and templatization

Hastening React SSR with component memoization and templatization: React is a best-of-breed UI component framework allowing WalmartLabs to build higher level components that can be shared and reused across pages and apps. In this presentation, Max Najim and Naga Malepati from WalmartLabs will peel through the React codebase to add a component caching/memoization optimization. The will use a require(..) hook to inject their optimization while avoiding the need to fork the React codebase.

82765b87655e66799efccebc4f95afcf?s=128

Maxime Najim

August 11, 2016
Tweet

Transcript

  1. HASTENING REACT SSR WITH COMPONENT MEMOIZATION AND TEMPLATIZATION

  2. Increasing User Demand www.radware.com Web App Performance

  3. •For every 1 second of improvement, experienced up to a

    2% increase in conversions •For every 100 ms of improvement, grew incremental revenue by up to 1% Time is Money Source: http://www.globaldots.com/how-website-speed-affects-conversion-rates
  4. Server-Side Rendering (SSR) •Better user experience of the initial page

    load
 •Better search engine ranking
  5. SSR with React

  6. Server-Side React Bad User Experience!

  7. Server-Side React CPU profile for one request On large pages,

    renderToString(.) blocks nodeJS’s event-loop and starves out incoming requests to the server.
  8. Server-Side React • Facebook: “Funny story about Server Rendering -

    it wasn’t actually designed that way.” (Sebastian Markbåge) • Facebook: “we don’t use it that heavily, which is why we haven’t really invested strongly in it.” (Sebastian Markbåge) React.js Conf 2015 
 Q&A with the team https://youtu.be/EPpkboSKvPI?t=7m48s
  9. Server-Side React 0 325ms 650ms 975ms 1s 300ms React React

    (best practices) mustache https://github.com/ndreckshage/react-boston-ssr
  10. • Looked at react-dom-stream and redfin/react-server to improve TTFB and

    ATF improvement • Challenges • Forks react and introduces new interfaces, i.e. not “React at heart” • Doesn't solve CPU total time Server-Side React ReactJS SF meetup in January 2016 https://github.com/aickin/react-dom-stream
  11. React Rendering Lifecycle getDefaultProps() getInitialState() componentWillMount() render() componentDidMount() Create Component

    Instance Create Transaction Mount Component (Gen Markup) Transaction.enqueue componentInstance Transaction.dequeue
  12. Mount Component React EL with Props Markup Given a set

    of properties, the markup generated is always the same Component Cache Double Clicking into Mount Component
  13. Memoizing Components The same “text” prop will always return the

    same helloworld html string class HelloWorldComponent extends React.Component { render() { return <div>Hello {this.props.text}!</div>; } } When text is “World” the output is: <div>Hello World!</div>
  14. Memoizing Components The same “text” prop will always return the

    same helloworld html string class HelloWorldComponent extends React.Component { render() { return <div>Hello {this.props.text}!</div>; } } When text is “World” the output is: <div>Hello World!</div> var componentOptimization = require("electrode-react-ssr- optimization"); var componentOptimizationRef = componentOptimization({ components: { 'HelloWorldComponent': {
 keyAttrs: ["text"] } } });
  15. Memoizing Demo

  16. Templatizing Components var React = require('react'); var ProductView = React.createClass({

    render: function() { return ( <div className="product"> <img src={this.props.product.image}/> <div className="product-detail"> <p className="name">{this.props.product.name}</p> <p className="description">{this.props.product.description} </p> <p className="price">Price: ${this.props.product.price}</p> <button type="button" onClick={this.addToCart} disabled={this.props.inventory > 0 ? '' : 'disabled'}> Add To Cart </button> </div> </div> ); } }); module.exports = ProductView;
  17. Templatizing Components var React = require('react'); var ProductView = React.createClass({

    render: function() { return ( <div className="product"> <img src={this.props.product.image}/> <div className="product-detail"> <p className="name">{this.props.product.name}</p> <p className="description">{this.props.product.description} </p> <p className="price">Price: ${this.props.product.price}</p> <button type="button" onClick={this.addToCart} disabled={this.props.inventory > 0 ? '' : 'disabled'}> Add To Cart </button> </div> </div> ); } }); module.exports = ProductView; • Dynamic props that would be different for each product.
 • Switch the corresponding props with template delimiters 
 (i.e. ${ prop_name }) during react component rendering cycle. • The template is then compiled, cached, executed and the markup is handed back to React.
  18. Templatizing Components • Dynamic props that would be different for

    each product.
 • Switch the corresponding props with template delimiters 
 (i.e. ${ prop_name }) during react component rendering cycle. • The template is then compiled, cached, executed and the markup is handed back to React. <div className="product"> <img src=${product_image}/> <div className="product-detail"> <p className="name">${product_name}</p> <p className="description">${product_description}</p> <p className="price">Price: ${selected_price}</p> <button type="button" onClick={this.addToCart}> Add To Cart </button> </div> </div>
  19. Templatizing Components var React = require('react'); var ProductView = React.createClass({

    render: function() { return ( <div className="product"> <img src={this.props.product.image}/> <div className="product-detail"> <p className="name">{this.props.product.name}</p> <p className="description">{this.props.product.description} </p> <p className="price">Price: ${this.props.product.price}</p> <button type="button" onClick={this.addToCart} disabled={this.props.inventory > 0 ? '' : 'disabled'}> Add To Cart </button> </div> </div> ); } }); module.exports = ProductView; var componentOptimization = require("electrode-react-ssr- optimization"); var componentOptimizationRef = componentOptimization({ components: { "ProductView": { templateAttrs: ["product.image",
 "product.name", 
 "product.description", 
 "product.price"] }, } });
  20. Templatizing Components var React = require('react'); var ProductView = React.createClass({

    render: function() { return ( <div className="product"> <img src={this.props.product.image}/> <div className="product-detail"> <p className="name">{this.props.product.name}</p> <p className="description">{this.props.product.description} </p> <p className="price">Price: ${this.props.product.price}</p> <button type="button" onClick={this.addToCart} disabled={this.props.inventory > 0 ? '' : 'disabled'}> {this.props.inventory ? 'Add To Cart' : 'Sold Out'} </button> </div> </div> ); } }); module.exports = ProductView;
  21. Templatizing Components var componentOptimization = require("electrode-react-ssr- optimization"); var componentOptimizationRef =

    componentOptimization({ components: { "ProductView": { templateAttrs: ["product.image",
 "product.name", 
 "product.description", 
 “product.price”], keyAttrs: ["product.inventory"] }, } }); var React = require('react'); var ProductView = React.createClass({ render: function() { return ( <div className="product"> <img src={this.props.product.image}/> <div className="product-detail"> <p className="name">{this.props.product.name}</p> <p className="description">{this.props.product.description} </p> <p className="price">Price: ${this.props.product.price}</p> <button type="button" onClick={this.addToCart} disabled={this.props.inventory > 0 ? '' : 'disabled'}> {this.props.inventory ? 'Add To Cart' : 'Sold Out'} </button> </div> </div> ); } }); module.exports = ProductView;
  22. Templatizing Components <div className="product"> <img src=${product_image}/> <div className="product-detail"> <p className="name">${product_name}</p>

    <p className="description">${product_description}</p> <p className="price">Price: ${selected_price}</p> <button type="button" onClick={this.addToCart}> Add To Cart </button> </div> </div> <div className="product"> <img src=${product_image}/> <div className="product-detail"> <p className="name">${product_name}</p> <p className="description">${product_description}</p> <p className="price">Price: ${selected_price}</p> <button type="button" onClick={this.addToCart}> Sold Out </button> </div> </div> Cached Template 1 - Sold Out Cached Template 2 - Add To Cart
  23. Templatizing Demo

  24. green blocks indicating markup that was cached on the server

  25. Server-Side React CPU profile for one request with rendering optimization

  26. Thank You https://github.com/walmartlabs/electrode-react-ssr-optimization