Slide 1

Slide 1 text

React ESI
 Blazing Fast SSR

Slide 2

Slide 2 text

React ESI @dunglas Kévin Dunglas ❏ Les-Tilleuls.coop’s Founder ❏ Symfony Core Team (PHP ) ❏ API Platform and Mercure creator @dunglas

Slide 3

Slide 3 text

React ESI @dunglas ✍ Self-managed since 2011 ‐ 36 people, 1,000% in 6 years ➡ [email protected]

Slide 4

Slide 4 text

React ESI @dunglas Single Page Apps

Slide 5

Slide 5 text

React ESI @dunglas Server-Side (PHP) vs Client-Side (JS) Rendering © Microsoft

Slide 6

Slide 6 text

React ESI @dunglas Single Page Apps are So Cool ❏ Update only what is needed (web components) ❏ No full page reload ❏ No « white flash » ❏ Smaller network payloads (JSON vs HTML) ❏ Rich UX

Slide 7

Slide 7 text

React ESI @dunglas SPAs is the 1st step for Progressive Web Apps © Google

Slide 8

Slide 8 text

React ESI @dunglas PWA are Powered by Service Workers

Slide 9

Slide 9 text

React ESI @dunglas Creating Fast SPAs/PWAs is Now Easy

Slide 10

Slide 10 text

React ESI @dunglas But SPAs Have Major Drawbacks: SEO « Currently, it's difficult to process JavaScript and not all search engine crawlers are able to process it successfully or immediately.
 In the future, we hope that this problem can be fixed, but in the meantime […]. »

Slide 11

Slide 11 text

React ESI @dunglas But SPAs Do Have Drawbacks: Initial Load Time

Slide 12

Slide 12 text

React ESI @dunglas Server-Side Rendering

Slide 13

Slide 13 text

React ESI @dunglas © Wallmart Labs

Slide 14

Slide 14 text

React ESI @dunglas © Wallmart Labs © Wallmart Labs

Slide 15

Slide 15 text

React ESI @dunglas SSR Benefits ❏ Typical SEO (like in PHP) ❏ Fast Initial Display (theoretically) ❏ SPA/PWA when fully loaded ❏ One code base, client-side/server-side (theoretically… again)

Slide 16

Slide 16 text

React ESI @dunglas SSR with React import React from "react"; import ReactDOMServer from "react-dom/server"; const Index = () => (

Hello

); const pageContent = ReactDOMServer.renderToString();

Slide 17

Slide 17 text

React ESI @dunglas SSR With React

Slide 18

Slide 18 text

React ESI @dunglas SSR Drawbacks: Performance ❏ All the page must be computed, every time, before sending it to the client ❏ The server must wait for all data needed to display the page ❏ The cache can be set only per full page, not per component

Slide 19

Slide 19 text

React ESI @dunglas What You Really Want © Akabia.fr

Slide 20

Slide 20 text

React ESI @dunglas How to Implement That With React/Vue/…?

Slide 21

Slide 21 text

React ESI @dunglas Edge Side Includes Here Come ESI

Slide 22

Slide 22 text

React ESI @dunglas ESI at a Glance © merge.nl weblog

Slide 23

Slide 23 text

React ESI @dunglas Edge Side Includes ❏ Kind of server-side iframe ❏ Page composition is usually handled by a cache server (edge server) ❏ Every fragment can have a different TTL ❏ Use standard HTTP cache headers

Slide 24

Slide 24 text

React ESI @dunglas Edge Side Includes ❏ Created by Akamai ❏ Supported by Varnish (open source), Squid, CloudFlare, Fastly, Akamai… ❏ Open format, submitted to the W3C in 2001 (not accepted) ❏ Implemented in Symfony since 2011

Slide 25

Slide 25 text

React ESI @dunglas 
 Just Add the Tag, the Cache Server Will Handle Everything Else Could be implemented directly using Node, or CloudFlare Workers

Slide 26

Slide 26 text

React ESI @dunglas Blazing-fast Server-Side Rendering for React and Next.js React ESI

Slide 27

Slide 27 text

React ESI @dunglas React ESI ❏ Server-side, replace React components you want by an ESI tag ❏ Specify a different TTL per component ❏ The corresponding HTML is generated asynchronously ❏ The cache server fetches and stores in its cache all the needed fragments

Slide 28

Slide 28 text

React ESI @dunglas React ESI © The Varnish book

Slide 29

Slide 29 text

React ESI @dunglas React ESI: the Higher Order Component import React from 'react'; import withESI from 'react-esi'; import MyFragment from 'components/MyFragment'; const MyFragmentESI = withESI(MyFragment, 'MyFragment'); // The second parameter is an unique ID identifying this fragment. // If you use different instances of the same component, use a different ID per instance. const Index = () => (

React ESI demo app

);

Slide 30

Slide 30 text

React ESI @dunglas A Fragment export default class MyFragment extends React.Component { render() { return (

A fragment {this.props.greeting /* access to the props as usual */}

); } }

Slide 31

Slide 31 text

React ESI @dunglas Setting a TTL export default class MyFragment extends React.Component { render() { return ( … ); } static async getInitialProps({ props, req, res }) { return new Promise(resolve => { // Set a TTL for this fragment if (res) res.set('Cache-Control', 's-maxage=60, max-age=30'); }); } }

Slide 32

Slide 32 text

React ESI @dunglas Computing initial props export default class MyFragment extends React.Component { render() {/*..*/} static async getInitialProps({ props, req, res }) { return new Promise(resolve => { setTimeout( // Simulate a delay (call to a remote service such as a web API) () => resolve({ ...props, // Props coming from the parent, passed through the internal URL dataFromAnAPI: 'Hello there’ }), 2000 ); }); } }

Slide 33

Slide 33 text

React ESI @dunglas Serving The Fragments (internal URL) import express from 'express'; import { path, serveFragment } from 'react-esi/lib/server'; const server = express(); server.get(path, (req, res) => // "path" default to /_fragment, change it using the REACT_ESI_PATH env var serveFragment( req, res, // "fragmentID" is the second parameter passed to the "WithESI" HOC, the root component used for this fragment must be returned fragmentID => require(`./components/${fragmentID}`).default) );

Slide 34

Slide 34 text

React ESI @dunglas State Reconciliation

Slide 35

Slide 35 text

React ESI @dunglas State Reconciliation ❏ Prevent fetching data clients-side and server-side ❏ During the 1st request (server-side), data are fetched and initial props are computed ❏ The initial props are serialized and injected in the server-side HTML (in a tag) ❏ Client-side, React ESI automatically finds and reuses these props when initializing the components

Slide 36

Slide 36 text

React ESI @dunglas Next.js Integration

Slide 37

Slide 37 text

React ESI @dunglas

Slide 38

Slide 38 text

React ESI @dunglas Thanks! Any questions?