Sunteți pe pagina 1din 158

More Than You Ever Wanted

to Know About Resource Hints


Harry Roberts • @csswizardry
Hi, I’m Harry

Consultant Performance Engineer


Leeds, UK
csswizardry.com
@csswizardry
i
Pro-Tip / Short Summary
!
Caveat / Warning / Bug
Resource Hints
“These primitives enable the developer […] to


assist the user agent in the decision process of
which origins it should connect to, and which
resources it should fetch and preprocess to
improve page performance.”
i
Single lines of HTML
that can dramatically
speed up your site
<head>

...

<link rel="preconnect" href="https://www.youtube.com/" />

<link rel="prefetch" href="app.ae72eb.js" />

<link rel="preload" href="/assets/webfont.woff2" as="font"


type="font/woff2" crossorigin />

...

</head>
csswz.it/rh
Overview
1.dns-prefetch
2.preconnect
3.prefetch
4.preload
5.subresource
6.prerender
dns-prefetch
csswz.it/dns-prefetch
i
Resolve the IP address
for a given domain
ahead of time
i
When you know the
domain but not the URL
<link rel="dns-prefetch" href="https://youtube.com" />
154 <iframe
155 src="https://www.youtube.com/embed/5g8a9luSZVI"
156 width="560" height="315">
157 </iframe>
5g8a9luSZVI
DNS Lookup
216.58.198.110

“[…] common names […] can answer in closer to
80–120ms.  […] an uncommon name […] can
average closer to 200–300ms.”

— csswz.it/2GuZo21
“More interestingly, for any of these queries


that access the internet, dropped packets, and
overworked (under provisioned) name resolvers,
regularly increases the total resolution time to
between 1 and 10 seconds.”

— csswz.it/2GuZo21
@andydavies
!
dns-prefetch is
implemented as
prefetch in IE9…
preconnect
csswz.it/preconnect
i
Resolve the IP address
and open a TCP/TLS
connection for a given
domain ahead of time
i
When you know the
domain but not the URL
<link rel="preconnect" href="https://fonts.googleapis.com" />
5g8a9luSZVI
TCP Handshake TLS Negotiation
hpbn.co
preconnect with

dns-prefetch fallback
<link rel="preconnect dns-prefetch" href="//twitter.com" />
!
Breaks in Safari
@andydavies
<link rel="preconnect" href="https://twitter.com" />
<link rel="dns-prefetch" href="https://twitter.com" />
!
Be judicious with
preconnect
Be Judicious

Only warm up frequent, significant, and likely origins


Don’t warm up fourth, fifth, sixth party origins
Opening many connections can have a CPU and battery cost
Chrome can only conduct six simultaneous DNS resolutions
!
Firefucked
prefetch
csswz.it/prefetch
i
A file needed for
subsequent navigation
<link rel="prefetch" href="/assets/video-player.js" />
<!-- search-results.html -->

<link rel="prefetch" href="/assets/video-player.js" />


i
Download the file and
drop it into HTTP cache
for later usage

“The user agent SHOULD NOT apply
preprocessing on the response and MUST
NOT automatically execute or apply it against
the current page context.”
Downloaded by this…
<!-- search-results.html -->
<link rel="prefetch" href="/assets/video-player.js" />

<!-- video.html -->


<script src="/assets/video-player.js"></script>

… executed by this.
Caching

prefetch will not execute or otherwise process the resource


It will drop it into HTTP cache as per its caching headers
Except…
“…those with the no-store Cache-
Control header. A resource will


be revalidated before use if there is
a Vary response header, no-cache Cache-
Control header, or if the resource is more than
five minutes old.”

— csswz.it/nostate-prefetch
i
Fetched with lowest
possible priority
i
In-flight prefetches
persist across
navigations
!
…prefetch acts like
dns-prefetch in IE9
<link rel="prefetch"

href="https://code.jquery.com/jquery-3.4.0.js" />
preload
csswz.it/preload
i
A mandatory fetch for
a file needed for the
current navigation
i
A way to surface late-
discovered resources
<link rel="preload" href="/assets/webfont.woff2"
as="font" type="font/woff2" crossorigin />
<link rel="preload" href="/assets/webfont.woff2"
as="font" type="font/woff2" crossorigin />
Late-discovered
resource?
1000ms

}
HTML
CSS
Font
1250ms

}
HTML
CSS
Background
1350ms

} VDOM
HTML
JS
CSS
Font
preload helps the
browser find them sooner
<script src="assets/app.js"></script>

<link rel="preload" href="assets/app.css"


as="style" />

<link rel="preload" href="assets/font.woff2"


as="font" type="font/woff2" crossorigin />
750ms

} VDOM
HTML
JS
CSS
Font
The as Attribute
<link rel="preload" href="/assets/webfont.woff2"
as="font" type="font/woff2" crossorigin />
"audio"
"document"
"embed"
"fetch"
"font"
as="image"
"object"
"script"
"style"
"track"
"video"
"worker"

“The attribute is necessary to guarantee correct
prioritization, request matching, application of
the correct CSP3 policy, and setting of the
appropriate Accept request header.”
!
Don’t try to be sneaky
<link rel="preload" href="style.css" as="style" />
<link rel="preload" href="app.js" as="script" />
<link rel="preload" href="image.jpg" as="image" />
<link rel="preload" href="style.css" as="image" />
<link rel="preload" href="app.js" as="style" />
<link rel="preload" href="image.jpg" as="script" />
i
Priority Hints will help
<link rel="preload" href="masthead.jpg"
as="image" importance="high" />

<link rel="preload" href="lazy.css"


as="style" importance="low" />
The type Attribute
<link rel="preload" href="hero.webp"
as="image" type="image/webp" />
The crossorigin Attribute

“Preload links for CORS enabled resources, such
as fonts or images with a crossorigin attribute,
must also include a crossorigin attribute, in
order for the resource to be properly used.”
i
Keep an eye on Console
!
Beware Google Chrome
Chrome Issues

Chrome over-prioritises preload


Dispatches preloads before other critical resources
Often returns less-critical resources sooner
@andydavies
@andydavies
0.4s slower to
start render

@andydavies
subresource
i
Precursor to preload…
!
…but completely
deprecated.
<link rel="subresource" href="/assets/webfont.woff2" />
SU B R E S O U R C E

“…not useful, proprietary, and buggy.”

— Yoav Weiss, csswz.it/2VOEyQc


prerender
csswz.it/prerender
i
Download and build
entire webpages in the
background…
i
…kinda…
i
…it’s complicated.
<link rel="prerender" href="/login/" />
PRER E N D E R
Problematic Prerender
Huge memory footprint with rendering whole new pages
Bandwidth usage spikes for site and user
Register multiple analytics hits, ad impressions
How do we handle timers, HTTP auth, interstitials, autoplay media?
How do we handle animations? Do we expect the carousel to start
running? Or do we write more code to wait for page visibility?
What if we get MitM and are made to prerender a malicious page?
How would the user know? They wouldn’t!
Prerender is dead,

long live prerender!
Prerender is dead,

long live prerender!
ate Prefe tch
N o St
i
prerender is the API;
NoState Prefetch is the
mechanism
!
prerender will not
render anything
!
prerender will not
render anything
!
NoState Prefetch
i
A recursive prefetch
B1

B2

A B B3

B4

B5
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, minimum-scale=1.0" />

<title>Prerender</title>

<link rel="prerender" href="https://csswizardry.com" />

</head>
<body>

<h1>Prerender</h1>

</body>
</html>
i
Fetched with lowest
possible priority
Tips, Tricks, and Gotchas
i
Deploy as HTTP
Headers
@andydavies
!
Edge only supports
HTTP header for
preconnect
!
Edge doesn’t support
HTTP header for
preload
i
Generate Dynamically
instant.page
!
Have an escape hatch
if ($omgWeAreBeingDDoSed == false) {

<script src="https://instant.page/1.1.0" defer></script>

}
!
You Need a Scheme
<link rel="preconnect" href="domain.com" />

==

<link rel="preconnect" href="./domain.com" />


<link rel="preconnect" href="https://domain.com" />
All Together!
Implementing Resource Hints

1.Identify a key page


2.Audit important assets and origins
3.Assess likely user flows
4.Design bespoke Resource Hint strategies
Web font
Likely next navigation

Critical third party


Web font Likely next navigation

Critical third party

JS image gallery
Resource Hint Strategy

1.HTTP header preconnect to cloudinary


2.Regular preconnect for other third parties
3.preload to discover web font sooner
4.prefetch for gallery.js
5.prerender or prefetch for likely next navigation
// HTTP response header

link: <https://res.cloudinary.com>; rel=preconnect


<!-- Preconnect other third party origins -->

<link rel="preconnect"
href="https://www.google-analytics.com">

<link rel="dns-prefetch"
href="https://www.google-analytics.com">
<!-- Early-discover web font -->

<link rel="stylesheet" href="/assets/app.css" />

<link rel="preload" href="/assets/webfont.woff2"


as="font" type="font/woff2" crossorigin />
<!-- Prefetch image gallery for next page -->

<link rel="prefetch" href="/assets/gallery.js" />


<!-- Prerender first three search results -->

<link rel="prerender" href="/products/one.html" />


<link rel="prerender" href="/products/two.html" />
<link rel="prerender" href="/products/three.html" />
<head>

<link rel="preconnect" href="https://www.google-analytics.com">


<link rel="dns-prefetch" href="https://www.google-analytics.com">

<link rel="stylesheet" href="/assets/app.css" />


<link rel="preload" href="/assets/webfont.woff2"
as="font" type="font/woff2" crossorigin />

<link rel="prefetch" href="/assets/gallery.js" />

<link rel="prerender" href="/products/one.html" />


<link rel="prerender" href="/products/two.html" />
<link rel="prerender" href="/products/three.html" />

</head>
<head>

<link rel="prefetch" href="/assets/product-01-large.jpg" />


<link rel="prefetch" href="/assets/product-02-large.jpg" />
<link rel="prefetch" href="/assets/product-03-large.jpg" />

</head>
Thank You!
@csswizardry
csswizardry@gmail.com harry.is/for-hire
speakerdeck.com/csswizardry

S-ar putea să vă placă și