Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Hastening React SSR with component memoization ...

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.

Maxime Najim

August 11, 2016
Tweet

More Decks by Maxime Najim

Other Decks in Programming

Transcript

  1. •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
  2. 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.
  3. 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
  4. Server-Side React 0 325ms 650ms 975ms 1s 300ms React React

    (best practices) mustache https://github.com/ndreckshage/react-boston-ssr
  5. • 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
  6. React Rendering Lifecycle getDefaultProps() getInitialState() componentWillMount() render() componentDidMount() Create Component

    Instance Create Transaction Mount Component (Gen Markup) Transaction.enqueue componentInstance Transaction.dequeue
  7. 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
  8. 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>
  9. 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"] } } });
  10. 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;
  11. 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.
  12. 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>
  13. 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"] }, } });
  14. 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;
  15. 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;
  16. 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