I'm Miguel Ángel Durán 🙋‍♂️

 

Enabler Frontend
at Adevinta Spain 🇪🇸👨‍💻

 

☕ coffee addict
⚛️ React fanboy
👾 fanatic Gamer
🚀 and performance freak 🤪!

@midudev

youtube.com/c/midudev

Performance focus at Adevinta Spain

Dynamic Rendering

Getting the most out of performance 🚀
while keeping bots happy 🤖

⚡️

and friends...

the problem

Understanding

the problem

is...

rendering stuff on the client is expensive

and

quick recap
rendering on the web

let's do a

about

Server Side Rendering (SSR)

👍 TTI & FCP

👍 Fully streaming
 

👎 Slow TTFB

👎 Inflexible

👎 Infrastructure

👎 Interactive with different language

Great for static content with little or zero client interaction

Static Rendering

Individual HTML files must be generated for every possible URL. Great for blogs, landings and static pages.

👍 TTI & FCP

👍 Fully streaming

👍 Fast TTFB!

👍 Static files

 

👎 Inflexible

👀 hydratation could be needed

export

Client Side Rendering

SPA fully rendered on the client. Very easy to set up, fast to develop, plenty of possibilities. No strong SEO requirements.

👍 Flexible

👍 TTFB
👍 Just static files


👎 Slow TTFB

👎 TTI way after FCP

trying to get the best of two worlds

SSR 🌍 + CSR 🌎

SSR with (re)hydration

finally

that's (re)hydration
and it looks like this...

SSR with (re)hydration

👍 Flexible

👍 Universal code


👎 Slow TTFB

👎 TTI >>>>> FCP

👎 Infrasructure

SPA fully rendered on the server,
fully booted on the client as well
🤭

someone in the audience that uses        ...
but doesn't want to say it

SSR with (re)hydration

SPA fully rendered on the server,
fully booted on the client as well
🤭

🔥

👍 Flexible

👍 Universal code


👎 Slow TTFB

👎 TTI >>>>> FCP

👎 Infrasructure


is getting the best...

or the worst of both?

 

 

a solution

Finding

solution

and the

is...

render less things

on the client and/or the server

but... how?

🤖 keep my SEO

⚛️ keep the flexibility of my app

👩‍💻 give the best experience to my users

I still want to...

Dynamic Rendering

ftw!

Dynamic Rendering

wt* is...

if you're a bot 🤖, you'll get a SSR or prerendered page

if you're a human being 👫, you'll get a CSR

🤖

👫

does              like it?

I hope it does.

It's their idea! 💡

Strategies

Dynamic Rendering

by Route

by Component

Dynamic

Rendering

by route

// 🚇 middleware to activate Dynamic Rendering on Express
const BOTS_USER_AGENTS = [
  'googlebot',
  'google-structured-data-testing-tool',
  'mediapartners-google'
]

const INDEX_HTML_PATH = path.join(__dirname, 'public', 'index.html')
const HTML_TEMPLATE = fs.readFileSync(INDEX_HTML_PATH, 'utf8')

export default function(req, res, next) {
  const rawUserAgent = req.get('user-agent')
  const userAgent = rawUserAgent.toLowerCase()

  // check if the request comes from a bot 🤖
  if (BOTS_USER_AGENTS.find(ua => userAgent.includes(ua))) {
    // if not an user, just use the normal behaviour (SSR?)
    return next()
  }

  // return index.html directly if is an user 👩‍💻
  return res.send(HTML_TEMPLATE)
}
// 🚆 Using the middleware in Express
const dynamicRendering = require('./dynamic-rendering')

// Use dynamic rendering for a specific path for testing
app.get(
    '/es/:op/:type/barcelona-capital/*',
    dynamicRenderingExperiment
)

// Isomorphic routes handler
app.get('*', SSR)

Dynamic Rendering

at route level

DEMO

Dynamic

Rendering

by route

♻️ TTFB

🧹 Hydration data is gone


🤔 Just a CSR for the user

🚩 FP & FCP

🧪 Useful technique for perf experiments

🆓 Free resources from your server

⏳ Help GoogleBot to index your content faster

☝️ More about this, later 👉

Dynamic

Rendering

at component level

Dynamic

Rendering

at component level

if you're a bot 🤖

the component is SSR

if you're a human being 👫
the component will be
rendered when visible

 

// ⚛️ Using <DynamicRendering /> component 
// userAgent must be retrieved universally on server and client

<DynamicRendering userAgent={universalUserAgent}>
    <a href='https://very-interesting-url.com'>
        <VeryComplexToComputeComponent />
        <img src='https://huge-image.com/panda.jpg'/>
    </a>
</DynamicRendering>

@schibstedspain/react-perf-dynamic-rendering
http://bit.ly/sui-dynamic-rendering

<DynamicRendering disabled>
  <img src='https://huge-image.com/panda_02.jpg'/>
</DynamicRendering>

<DynamicRendering height={50}>
  <img src='https://huge-image.com/panda_02.jpg'/>
</DynamicRendering>

<DynamicRendering height={50} forceRender={true}>
  <p>This will be rendered on client & server even
    when is out the viewport
  </p>
  <p>Or in the server even when is a regular user agent</p>
  <img src='https://huge-image.com/panda_02.jpg'/>
</DynamicRendering>

@schibstedspain/react-perf-dynamic-rendering
http://bit.ly/sui-dynamic-rendering

// ⚛️ <DynamicRendering /> implementation

export default function DynamicRendering(props) {
  const { children, disabled, forceRender, height, userAgent } = props

  // check if the userAgent is a bot and if we're in the browser
  const isBot = checkUserAgentIsBot({userAgent})
  const isOnBrowser = typeof window !== 'undefined'

  // Force render in server and client
  if (forceRender) return children

  // if isBot or disabled, we return in server and client the content
  if (isBot) return children

  // now, we're sure the user isNotBot
  // so check if we're on the browser side and if is not disabled the component
  if (isOnBrowser && !disabled) {
    return <LazyContent height={height}>{children}</LazyContent>
  } else {
    // so, we're on the server side or the component is disabled
    return <div style={{height: `${height}px`}} />
  }
}

Dynamic Rendering

at component level

@schibstedspain/react-perf-dynamic-rendering

🔗 http://bit.ly/sui-dynamic-rendering

Only 1️⃣ requirement:

It's open source!

you need to use React ⚛️

Dynamic Rendering

at component level

DEMO

seek 0:52

Dynamic

Rendering

at component level

 Improve TTI

😴 Lazy Load for the user


🚩 Keep Hydration data

🏋️‍♀️ Perfect for stuff below the fold 

🆓 Free resources from your server

⏳ Help GoogleBot to index your content faster

☝️ More about this, later 👉

The new GoogleBot is superb!

🧩 JS Modules

📐 Intersection Observer

🧱 Custom Elements

🌚 Shadow DOM

🏫 Classes

🏷 Tagged Template Literals

Why do we need this?

links detected

at a later time

💸 expensive!

https://youtu.be/LXF8bM4g-J4

130 trillion web pages to crawl

rendering all those pages, takes time

WRS

Google Bot 101

https://youtu.be/LXF8bM4g-J4

If you want/need your site

to be crawled fast and indexed faster

you better bet on SSR

tl;dl 👂

for now

Static

Rendering

at component level

// ⚛️ <StaticContent /> usage
import StaticContent from './StaticContent'

function Footer () {
  return (
    <StaticContent>
      <HugeListOfLinks data={listOfLinks} />
    </StaticContent>
  )
}
// ⚛️ <StaticContent /> component
import React from 'react'

export default function StaticContent({children}) {
  // we're in the server, just render the content
  if (typeof window === 'undefined') {
    return <div>{children}</div>
  }

  // avoid re-render on the client
  return (
    <div
      suppressHydrationWarning
      dangerouslySetInnerHTML={{__html: ''}}
    />
  )
}

Static Rendering

DEMO

Static

Rendering

at component level

👍 Avoid re-hydrate for static components

👍 Thus could greatly improve TTI


👎 Lose interactivity

👎 Hydration data still there

👎 Element wrapper (ex. <div>)

📸 For expensive rendering lists or static content

🤖 GoogleBot is definitely going to detect it

That's all!

Thanks!

gifs borrowed from @eh_cat!

@midudev

youtube.com/c/midudev

Dynamic Rendering: Getting the most out of performance while keeping bots happy

By Miguel Angel Durán García

Dynamic Rendering: Getting the most out of performance while keeping bots happy

Version: Frontend Connect Presentation Wien 2019

  • 600