Prefetch, preload, prerender, etc
Woow: DNS Prefetch, Preconnect, Preload, HTTP/2 Server Push, Prefetch and Prerender.
All those technologies can all be collectively called Resource Hints and the last two; prefetch & prerender, can also recognized as prebrowsing; coined from term predictive browsing.
===
Resource hints can be divided into exactly 6 types. Note that the only one not implemented is HTTP/2 Server Push as it is as of time of writing, still unsupported by major web servers, apache and nginx.
To recap, techniques are:
- DNS Prefetching / current page (
dns-prefetch
) - Domain Preconnect / current page (
preconnect
) - Resource Preload / current page (
preload
now supersedessubresource
that is depreciated) - HTTP/2 Server Push / current page
- Link prefetching / next page (
prefetch
) - Prerendering / next page
As most of there technologies should be somehow aware of the real site content and/or user behavior, the best way to trigger them is from Wordpress, not from server side.
There are couple of optimizations that can be achieved most easily directly from server, notably from Google Pagespeed module, and you should use these immediately.
I expect a lot of plugins for these purpose in the future, but for now, there are already couple of good ones in existence.
DNS prefetching
DNS resolution speed can be improved with DNS Prefetching, a technique adopted by most modern browsers.
There a couple of domains obvious to prefetch DNS and those include both your specific domain CDN and any public CDN’s you probably use (Google for example).
<link rel="dns-prefetch" href="//fonts.googleapis.com"> <!-- Google Fonts -->
<link rel="dns-prefetch" href="//www.google-analytics.com"> <!-- Google Analytics -->
<link rel="dns-prefetch" href="//www.googletagmanager.com"> <!-- Google Tag Manager -->
I read somewhere that it is not recommended to use more than 5 URLs for DNS prefetching, but that’s simply not true.
Good candidates for DNS prefetching are:
- Resources on different domains hidden behind 301 redirects
- Resources accessed from JavaScript code
- Resources for analytics which usually come from different domains, but this will browser figure out alone, without help.
Pagespeed filter insert_dns_prefetch puts <link rel="dns-prefetch">
tags in page head and it does it automatically for all domains present in the document.
Good article on this theme.
Preconnect
Preconnect is used to indicate origins for resources on current page. We use preconnect to pre-open a new TCP connection.
It is perfect when you are not sure of a full resource URL, but you surely know the origin domain from which the resources are going to be fetched.
We can call it extended DNS prefetch, as it very similar but so much powerful as it initiates a complete early connection, which includes the DNS lookup, TCP handshake, and optional TLS negotiation.
Usage example:
<link href='https://fonts.gstatic.com' rel='preconnect' crossorigin>
<link href='https://fonts.googleapis.com/css?family=Roboto+Slab:700|Open+Sans' rel='stylesheet'>
Application can also invoke preconnects dynamicly, with JavaScript.
Preload
The reference material is on link type preload
and on HTTP/2 Server Push is this document: Preload.
If you use this technique, preload only the most important resources and make sure they are cacheable by the browser. Images, CSS, JavaScript, and font files are good candidates for preload, but HTML responses are not since they aren’t cacheable.
Unlike DNS prefetching, resource prefetching is a more expensive operation; be mindful of how and when to use it.
<link rel='preload' href='critical.js'>
<link rel='preload' href='main.css'>
Preload is a mandatory and high-priority fetch for a resource that is necessary for the current navigation.
Note: Preloading was in the past known as Subresource prefetching. Old syntax rel=subresource
is deprecated as of january 2016 and is superseded with the new, rel=preload
syntax.
HTTP/2 Server Push
Server push is similar to Preloading, but it eliminates the request roundtrip between client and server for the declared preload
link resource.
Not sure how it’s working, but I expect we just have to enable server support for this option to work out of the box?
Prefetch
Prefetch is an optional browser mechanism, lowest priority fetch for a resource that might be used by a subsequent navigation. In another words, it usualy utilizes browser idle time to download resources that the user might visit in the near future.
Also known as link prefetching and is already adopted by most major browsers.
<link rel='prefetch' href='secondary.js'>
Prefetching does work across domains, including pulling cookies from those sites.
Prerendering
It is similar to prefetch but now the whole document with all its resources is fetched and rendered in background.
So we must very carefully to try to predict users actions and optimistically load resources ahead of time for better performance.
Luckily, we can trigger prerendering by inserting a link element with a rel='prerender'
, for example:
<link rel='prerender' href='http://www.mypage.com'>
Luckily, we can inject prerendering hints at runtime, based on user action, which is probably the most realistic usage scenario.
var hint =document.createElement("link")
hint.setAttribute("rel","prerender")
hint.setAttribute("href","next-page.html")
document.getElementsByTagName("head")[0].appendChild(hint)
For example, if a user hovers over an element long enough, we can start prerendering. Great usage of similar idea is a JS plugin that prerenders pages on link hovers - smoothState.js. It already has proper Wordpress integrations implemented here
Prerendering is the most costly of all techniques and misusing it can cause major bandwidth waste, especially on mobile devices.
We can test the prerendering with this simple tool.
Notes on prerendering
-
If you try to test for prerendering, please note that Chrome doesn’t use it when Developer Tools is open. You can see if a page is being prerendered at
chrome://net-internals/#prerender
. -
Google Analytics supports this and it won’t count visits or any other stat coming from a prerendered page.
Domains:
<link rel="dns-prefetch" href="//cdn.save-up.at">
<link rel="preconnect" href="//cdn.save-up.at" crossorigin>
Prefetch is for next navigation, but subresource prefetch is for current:
<link rel="prefetch" href="/library.js" as="script">
The prerender link relation type is used to identify a resource that might be required by the next navigation:
<link rel="prerender" href="//example.com/next-page.html">
In 2023 - <link rel="prerender">
is Chrome-specific and was never standardized, and the Chrome engineering team are in the process of sunsetting it.
Hint probability?
In addition to specifying the hint type, the application may indicate the expected probability that the specified resource hint will be used.
<link rel="dns-prefetch" href="//widget.com" pr="0.75">
<link rel="preconnect" href="//cdn.example.com" pr="0.42">
<link rel="prefetch" href="//example.com/next-page.html" pr="0.75">
<link rel="prerender" href="//example.com/thankyou.html" pr="0.25">
Details on prerendering
The following reference document on Chrome Prerendering gives us explanation and an answer to very important questions.
Does a prerender follow 301 redirect? Yes, by default; but you can stop that on request.
If the server sends a redirect response for a subresource with a “Follow-Only-When-Prerender-Shown: 1” header, Chrome will hold off on following the redirect and on fetching the respective subresource until the prerender is shown to the user.
Are cookies set? They are set only if prerendered page is displayed.
Cookies made by the pre-rendered page are not visible to other tabs until the user has activated the page. If the user never uses a pre-rendered page, cookies will just disappear.
We can check the current prerender status on chrome://net-internals/#prerender page.
As for Firefox, they use term prefetch, not prerender. Important document from 2010 on HTML5 Link Prefetching explains couple of important notes:
- Prefetching does work across domains, including pulling cookies from those sites.
- Prefetching can throw off website statistics as the user doesn’t technically visit a given page.
What’s in it for us?
-
DNS-prefetch our CDN, affiliate networks and public CDN’s
I did notice that Pagespeed is not adding a CDN subdomain here, and it should do it.
-
Preconnect to our CDN, for sure.
-
Prefetch domain of our affiliate link on a page On shop pages, do it like this:
-
Based on the fact that prefetching does work across domains, including pulling cookies from those sites.
Our
/coupon/123
is a 301 redirect and it isnoindex
. On Shop page we link to/coupon/123
asnofollow
. It is safe to prerender/coupon/123
and it will work. Index will not go there but browser will follow redirects and prerender valid page. Cookies would not be set, until user really visits that page.Please note that, if we have page-per-view links or tracking pixels, those statistics will be really off because of this.
You can always prerender home page as it will probably at some point go there.
-
-
Prerender some our page that will be next shop page: no idea what will be this? magazin page: home, menu items and/or then first shop that is displayed. We can prefetch & prerender all the pages from main menu links.
For now, only dns-prefech
and preconnect
are sure. The first one is easily done with pagespeed.
There is an perfect JS library schliflo/BoostR to help about dynamically using preconnect, preload and prerender.
Total explanation! Very important comment: Comments on the A List Apart Article One Step Ahead: Improving Performance with Prebrowsing
Prefetch is meant to be used for resources required by the next navigation, which means that they will be downloaded with low priority or not at all, and always after all other resources have finished loading. As a result, prefetch should not be used for hinting critical resources on the current page.
This is also the reason why Chrome introduced rel=subresource
, for current page, but subresource has its own set of problems. so I wouldn’t recommend that either.
In short: use dns-prefetch for current and next pages; use prefetch and prerender to fetch resources for next navigation.
Resource Hints - What is Preload, Prefetch, and Preconnect? What Is the Preload Directive? - KeyCDN Support
Some Wordpress support?
#34292 (Support for DNS Prefetching & Prerender)
How I Sped Up My Site 68.35% With One Line of Code - iPullRank
new in 2023
Resource Hints in Wordpress
Odlično objašnjenje je Using Resource Hints to Optimize WordPress Performance – getButterfly ali i How to preload a resource in WordPress (a few simple clicks) kao i Faster page loads using server think-time with Early Hints - Chrome for Developers.
WP core podržava rudimentarni resource Hints in WordPress koji uglavnom radi for all scripts and styles which are enqueued from external hosts. Svejedno, there are a few interesting plugins that are the first thing to try for improving LCP in page optimization jer oni mnogo bolje rade
-
Pre* Party Resource Hints with repo samperrow/pre-party-browser-hints: Plugin for WordPress users to easily implement the latest W3C resource hints. ne omogućava da definišeš script/css preko WP handle-a pa je praktično neupotrebljiv
-
Better Resource Hints je mnogo lepši i logičniji, ali pravi mi neku grešku i sprečava me da uđem u “Edit Post” iz nekoga razloga. Vidim da davno nije ažuriran, iako je najnormalniji.
-
Preload Requests ima isti problem kao Pre-Party, odnosno ne koristi handle za lokalni resurs
-
Oxyplug Prefetch & Prerender je još jedan ali isti.
Obavezno pročitaj dodatne izvore kao Introducing Better Resource Hints for WordPress i How to Better Leverage Browser Preloading .
A manje napredni pluginovi su:
- Preload Featured Images je već implementirano u “Performance” pluginu, ali možda i nije. Ono što radi je samo dodavanje <link rel=“preload” as=“image”, što je vrlo lako uraditi i ručno - što sam ja i uradio.
“Preload” is most important
Najbitnije je “preload” jer je to na samoj strani tog sajta za interne resurse, i on se može implemnentirati i kroz header i kao link rel u head-u.
Preload Key Requests WordPress Plugin - 3 Easy Options je dosta dobar pregled pluginova koji to rade ili ne rade.
Implementing Preload, Prefetch, Preconnect in WordPress takođe daje prikaz opcija, ali pominje i Better resource hints.
Napomene o načinu implementacije
Bitno je napomenitu da mora sa query stringom, kao što piše How to preload a resource in WordPress (a few simple clicks) and if you’re using cache-busting techniques (such as query strings domain.com/style.css?ver=1.0), don’t forget that browsers see exact URLs. So you will need to use the query string URL or you can preload dynamically with a handle.
Takođe, zbunjujući onload="this.onload=null;this.rel='stylesheet'"
je objašnjen u Defer non-critical CSS ali nije više potreban jer sada svi browseri podržavaju, iako tu tehniku preporučuje i filamentgroup/loadCSS: Load CSS asynchronously kroz The Simplest Way to Load CSS Asynchronously | Filament Group, Inc.
Još odličnih izvora je Accelerate your website’s loading speed: why using a Link Preload Tag is crucial - Iron/Out kao i glavni - Don’t fight the browser preload scanner
Page Speed Checklist - Website Performance Optimization je konkretan sajt sa savetima
–
ThemePlate/Resource: Helper for resource hinting
a tu ima baš dobrih klasa, samo od dokumentacije ništa…
add_action(‘send_headers’, function {
header(“link: </wp-content/themes/phpied2/style.css>; rel=preload; as=style, </wp-includes/css/dist/block-library/style.min.css?ver=5.4.1>; rel=preload; as=style”);
});
Another way could be to use the wp_preload_resources filter to add this via markup (instead of headers):
Plugin name: 103 Early Hints
Boost Website Performance with 103 Early Hints - Expert Guide - Iron/Out
Understanding CSS preload and other resource hints - LogRocket Blog
Increase performance with prefetch and preload | SpeedyWordpress
- treba mi plugin gde po bilo kom delu URL-a ili handle-a se pravi resource hint, a ne samo po konkretnom URL-u
Dakle, ako koristiš resource handle (ili deo istog) onda nema veze šta je u version ili slično. Obavezno obriši sve WP defaultove
add_action( ‘send_headers’, array( $this, ‘send_in_header’ ), 1, 0 );
add_action( ‘wp_head’, array( $this, ‘send_html_head’ ), 1, 0 );