Both will save you some time when accessing to external services and CDNs.
When instead of a domain we have a particular resource or route that could be needed in future navigations the prefetch value is used, as preload is for resources needed in the current page.
<link rel="prefetch" href="//your-site.com/next-route.html" />
If you would like to read more about resource hints or see more examples this oldie but goodie article by Luis Vieira is highly recommended.
Since we want to improve the inner navigation in a static site, we can combine prefetch with a little of JavaScript to load possible upcoming routes in advanced.
To move forward with this idea we would need to append a link
element everytime the user hovers an anchor.
The element to append should look like this:
<link rel="prefetch" href="//your-project.com/the-future-route" />
First thing, let's collect all the anchors from the current page and turn them into an array to loop over them easier.
const anchors = document.getElementsByTagName('a');
const anchorsArray = [].slice.call(anchors);
// yay, we can use array methods now!
Next, let's create a method that adds a link
element to the document with the corresponding href
to prefetch.
const prefetchRoute = function () {
const link = document.createElement('link');
link.href = this.href;
link.rel = 'prefetch';
document.head.appendChild(link);
};
Keep in mind that once we use this method in an event listener the keyword this will point to the anchor element being hovered.
Now we attach this function to all anchors' events.
anchorsArray.map((anchor) => {
anchor.addEventListener('mouseover', prefetchRoute);
});
The interval of time between the user hovering and clicking a link might not be much, but it's enough to start ahead the connection to the resource and speed up the navigation at practically no cost.
For the solution to work properly we should skip anchors with external links.
anchorsArray.map((anchor) => {
// only listen to hover when hosts match
if (anchor.host === document.location.host) {
anchor.addEventListener('mouseover', prefetchRoute);
}
});
We could also remove the listener after prefetching the route.
const prefetchRoute = function () {
const link = document.createElement('link');
link.href = this.href;
link.rel = 'prefetch';
document.head.appendChild(link);
// remove listener from anchor element
this.removeEventListener('mouseover', prefetchRoute);
};
This way we avoid injecting the same link
element several times.
Since the mouseover
event won't be dispatched in mobile devices we could also attach the prefetchRoute
method to the touchstart
action.
I've personally bailed on doing it because there's a chance the device is not connected to wifi while navigating and I prefer not to silently consume users' data plan, even when they are just some kilobytes.
If you are code splitting your application and using a bundler that allows named chunks like webpack does, you can prefetch that file to fasten dynamic routes.
Even when you're in control of your server environment, using resource hints it's highly recommended. Take in count that for them to work you might need to serve your project on https.
This little trick is currently speeding up the experience in this site on desktop, so you can inspect the head
element or check the network tab on developer tools while passing your pointer over internal links to see it in action.
Kudos to Rich Harris from whom I stole this approach he used in Sapper.