Performance focus at Adevinta Spain
โก๏ธ
๐ TTI & FCP
๐ Fully streaming
ย
๐ Slow TTFB
๐ Inflexible
๐ Infrastructure
๐ Interactive with different language
Great for static content with little or zero client interaction
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
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
๐ Flexible
๐ Universal code
๐ย Slow TTFB
๐ย TTI >>>>> FCP
๐ Infrasructure
SPA fully rendered on the server,
fully booted on the client as well ๐คญ
SPA fully rendered on the server,
fully booted on the client as well ๐คญ
๐ฅ
๐ Flexible
๐ Universal code
๐ย Slow TTFB
๐ย TTI >>>>> FCP
๐ Infrasructure
ย
ย
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)
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 ๐
at component level
at component level
// โ๏ธ 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`}} />
}
}
@schibstedspain/react-perf-dynamic-rendering
Only 1๏ธโฃ requirement:
It's open source!
you need to use React โ๏ธ
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 ๐
links detected
at a later time
๐ธ expensive!
https://youtu.be/LXF8bM4g-J4
WRS
https://youtu.be/LXF8bM4g-J4
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: ''}}
/>
)
}
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