150 Days of HTML

Chapter 8 | Resource Hints

What’s up next with rel? Resource Hints πŸ’‘ These keywords are all about performance and through performance, improving user experience and accessibility. Before we dig into the various resource hints I want to be clear that this will by no means be a deep dive into resource hints. That is a topic all its own πŸ˜‰ For this chapter, we will get to know the various resource hints as well as go over the basics of what they are used for.

Note: As the name suggests, these are hints we as developers provide to the browser so, for the most part, it is still up to the browser to decide whether to follow our hints or not.

In the related reading section I will provide some resources should you wish to explore this topic further.

🐒 dns-prefetch

DNS, or the Domain Name Service along with the Internet Protocol(IP) is the core addressing system used to connect you to the website you wish to visit. The size of the internet is immense and dynamic with new IP addresses and domain names constantly being added.

Your browser needs to know the IP address of the domain name you typed into the address bar in order to connect to it. Because of the vastness of the internet, it is therefore not always a quick and simple process for your browser to get hold of this IP address. DNS is made up of an array of DNS zones and servers strewn across the globe. The closest one to you might not be the one that has the address and related IP address in its database. So, the first DNS server may need to ask a second and a third before getting hold of the IP address it needs to send back to the browser. Commonly a DNS lookup takes between 20 - 120 milliseconds.

It is also very common these days for a single webpage to connect to multiple domain names in order to get external resources such as custom fonts, JavaScript libraries, etc. For each new domain the browser encounters, it needs to do an initial DNS lookup request. You can see how this can potentially add up.

This is then where dns-prefetch comes into play. If we know for example that we will be getting a JavaScript library from say unpkg, we can get some of the leg work out of the way by telling the browser about the domain name, and asking it to pretty please do the DNS resolution/lookup as early as possible.

Using the UNPKG example domain above, we will add the following to our head:

1
<link rel="dns-preconnect" href="https://unpkg.com/" />

🐭 preconnect

There is more to connecting to another server than just DNS though. DNS maintains a map of domain names to IP addresses and so, it can tell the browser the IP address at which the destination server exists but, that is where it ends. The next step is for the browser to initiate a connection to the IP address.

The first step in this process is what is known as the TCP(Transmission Control Protocol) handshake. This is the process whereby the client(browser) negotiates a connection with the server. Essentially, the client sends a request to the server saying, “Hey, can you please open a connection for me?”. The server then responds with, “Hi there! Sure, could you also open one for me on your end?”. To which the client responds, “Yup, done”. A two-way connection now exists between the client and the server.

If you are connecting to the other server via HTTPS(HyperText Transfer Protocol Secure), which is very common and almost universal these days, there is an additional handshake that needs to happen after the TCP handshake completes. This is known as the TLS(Transport Layer Security) handshake.

The process goes something like this. The client sends a “hello” message to the server. This time, it includes the TLS version and cipher suites it supports, as well as a string of random bytes(aka “client random”). The server responds with a “hello” which includes its SSL certificate, its chosen cipher suite, and the “server random”. The browser verifies the SSL certificate and if verified, sends back one more strings of random bytes knows as the “premaster secret”. The server decrypts the “premaster secret”. Both client and server generate session keys from the client random, server random, and premaster secret. The client sends an encrypted “finish” message, the server replies with an encrypted “finish” message, the handshake completes and the connection continues using the session keys.

That is a lot! 🀯 Thankfully this entire process takes only milliseconds but it does add to the overall latency of getting the data your application needs and your user is interested in. Using preconnect, we are asking the browser to take all of the above steps, including DNS lookup, as early as possible for the domain we specify. So, if that library you need to get from UNPKG is supercritical and you want to reduce as much of the latency as possible, as early as possible, you want to reach for preconnect as opposed to just dns-prefetch. Let’s change the above example to do a preconnect:

1
<link rel="preconnect" href="https://unpkg.com/" />

πŸ¦… prefetch

While the above is mainly concerned with the current page, prefetch and its close cousin prerender is concerned with resources used on the next navigation. The prefetch resource hint informs the browser of a resource that is highly likely to be required on future navigation and as such, it would be beneficial to preemptively fetch and cache the resource.

NOTE: While the browser might fetch and cache the resource, it will not process, parse or execute.

There are two optional attributes that can be used in combination with prefetch. These are as and crossorigin. We have covered crossorigin before and its use in this context is the same. While the as attribute is optional, it is useful in order to indicate the type of resource that will be prefetched. This allows the browser to optimize the fetching process by setting appropriate request headers, transport priority, etc.

Let’s look at prefetching a JavaScript resource for example:

1
2
3
4
5
6
<link
  rel="prefetch"
  as="script"
  crossorigin="anonymous"
  href="https://unpkg.com/three"
/>

πŸ• prerender

The next step up from prefetch is prerender. The first notable difference is that the browser will not only fetch the resource but, it will also execute it. But, prerender is only used for HTML documents. If you need to fetch a different type of resource, prefetch is your tool of choice. As such, the as and crossorigin attributes are not valid in this context.

NOTE: What the browser does with regard to sub-resources(images, scripts, style, etc.) is implementation and context dependant.

1
<link rel="prerender" href="https://example.com/search-results.html" />

🐈 preload

There is one more keyword that is related to the above resource hints. The preload keyword is different from the above in that it is not a hint, but an instruction to the browser to preload and cache the resource i.e. whereas the hints state that the browser should pretty please with sugar on top take the action, preload indicates that the browser must take the action.

The syntax of preload is the same as that of prefetch

1
2
3
4
5
6
<link
  rel="preload"
  href="https://unpkg.com/three"
  as="script"
  crossorigin="credentials"
/>

As with prefetch the browser will fetch and cache the resource but not execute. Preload is also only concerned with the current page. It is not to be used for resources that might be required later during subsequent navigation.

NOTE: While the resource hints are well supported across modern browsers, preload has some caveats.

With that, we are almost through the various possible keywords of the rel attribute. Next, we will look at the last four: modulepreload, next, pingback, and search.

Buy me a coffee and support the work on 150 Days of HTML.