Cuando se habla de Web Performance Optimization, generalmente referido como WPO, rápidamente viene a la cabeza el cacheo, la minificación o la compresión, por citar algunas de las más habituales. Estas técnicas se realizan server-side, aunque el efecto buscado es que el cliente pueda cargar la web más rápido, es decir, aunque el efecto buscado sea client-side.

Sin embargo, la precarga de recursos, más conocida por el nombre en inglés resource hints, que se podría traducir literalmente como “sugerencias de recurso”, es un técnica que funciona íntegramente client-side y que puede tener un impacto importante en WPO.

¿Cómo funciona?

De forma muy básica, el resource hints “sugiere” al navegador (no son directivas obligatorias) que descargue recursos que no van a ser utilizados en ese momento pero que “pueden” ser utilizados en el futuro. La descarga se realiza en segundo plano y antes de que el cliente necesite el recurso, de ahí que se hable de “precarga”.

Las sugerencias para precargar recursos se realizan a través de elementos <link> incluidos en el <head> y el atributo rel. Por ejemplo, le podemos decir al navegador que descargue una imagen:

<link rel="prefetch" href="https://example.com/media/image.jpg">

También se pueden incluir en las cabeceras HTTP:

Link: </media/image.jpg>; rel=prefetch

Posteriormente, cuando se incluya esta imagen en el documento, el usuario la tendrá al instante:

<img src="https://example.com/media/image.jpg" alt="...">

Hay que destacar que se puede utilizar para recursos de la página actual, pero también para recursos de otras páginas. Esto es extremadamente útil en aplicaciones en las que es fácil prever acciones futuras del usuario, lo que se conoce como prebrowsing.

Tipos de resource hints

Según las especificaciones de resource hints, hay cuatro tipos. Además, está disponible preload, el último en llegar y con unas especificaciones propias.

  1. dns-prefetch
  2. preconnect
  3. prefetch
  4. prerender
  5. preload

Veamos que hace exactamente cada uno, sus diferencias más importantes y algunos ejemplos.

1

dns-prefetch

El dns-prefetch se utiliza para indicar al cliente que resuelva el DNS de un dominio (Domain Name System) tan pronto como sea posible. Es útil cuando se van a cargar recursos desde dominios externos.

Por ejemplo, imagina que vamos a utilizar un widget de una red social, por ejemplo Twitter, cargado desde twitter.com. En el <head> podríamos incluir esto:

<link rel="dns-prefetch" href="https://twitter.com">

Ahora, el navegador ya sabe a que IP tiene que conectarse para solicitar recursos a twitter.com. El DNS lookup se ha realizado en segundo plano y está resuelto antes de que el recurso se necesite. Dicho de otro modo, cuándo se vaya a cargar el recurso, nos ahorraremos el DNS lookup time.

2

preconnect

El hint preconnect funciona de una forma similar a dns-prefetch pero va unos pasos más allá. Además de resolver el DNS, el navegador puede iniciar las negociaciones TCP y, opcional, las negociaciones TLS en el caso de conexiones seguras.

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

Cada una de estas negociaciones, conocidas habitualmente como “handshake”, son las que ocupan la mayor parte del tiempo necesario para establecer una conexión. Con el resource hint tipo preconnect indicamos al navegador las conexiones que necesitará posteriormente para que las prepare tan pronto como sea posible.

3

prefetch

Si conocemos de antemano recursos concretos que serán requeridos en el futuro, podemos pedirle al navegador que los descargue y almacene localmente. No solo que resuelva las DNS o que realice las negociaciones de conexión, sino que solicite y descargue el recurso en cuestión.

La directiva prefetch es una sugerencia de descarga de baja prioridad que el navegador realizará en segundo plano. En cuanto la página termine de cargarse, el navegador comenzará a descargar los recursos adicionales especificados en los links con prefetch. Se puede utilizar con cualquier tipo de recurso que pueda ser almacenado en la caché local del cliente, tales como imágenes o scripts:

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

prerender

Este tipo de resource hint es similar a prefetch pero, además de la descarga, realiza el análisis y construcción completa, o renderizado, de documentos HTML, incluyendo la construcción del DOM. Es útil cuándo es posible conocer con alta probabilidad el siguiente objetivo de navegación HTML.

<link rel="prerender" href="https//example.com/page.html">
5

preload

La directiva preload nació después que resource hints y permite un control mucho mayor sobre la precarga de recursos. Es similar a prefetch pero con una gran diferencia en el comportamiento: preload son directivas obligatorias y de alta prioridad, por lo que su uso está centrado en la navegación actual, mientras que prefetch, al ser sugerencias de baja prioridad, podría relegarse a recursos que puedan utilizarse en el futuro, es decir, en objetivos de navegación posteriores.

El link preload permite notificar al navegador como debe tratar el recurso precargado a través del atributo as:

<link rel="preload" href="/assets/myfont.woff" as="font">
<link rel="preload" href="/assets/myimage.jpg" as="image">
<link rel="preload" href="/assets/mycss.css" as="style">
<link rel="preload" href="/assets/myscripts.js" as="javascript">

Y no se queda en estos recursos “típicos”, se puede utilizar para <audio>, <video>, <iframe>, <embed> y otros muchos más:

<link rel="preload" href="/assets/myvideo.mp4" as="video">
<link rel="preload" href="https://youtu.be/DWGjYg2LmZQ" as="iframe">

Además, se puede establecer el tipo de contenido o la configuración crossorigin, incluso como tratar la carga: async, defer, etc:

<link rel="preload" href="https://fonts.example.com/font.woff2" as="font" crossorigin type="font/woff2">

Aunque la utilidad de la precarga de recursos es obvia, hay que tener cuidado y estudiar bien los hints incorporados. Poner demasiados puede tener un impacto negativo sobre el rendimiento, todo lo contrario al objetivo perseguido.

Un ejemplo en el que la preload puede ser muy útil es el caso de las webfonts. Una webfont no es descargada hasta que no se encuentre un elemento HTML asociado a un selector CSS en el que se declare la correspondiente regla @font-face.

Esto quiere decir que las fuentes no se descargan hasta que el DOM y el CSSOM han sido construidos. preload evitaría este cuello de botella descargando la fuente tan pronto como el navegador se encuentre con el link preload3:

<link rel="preload" href="//fonts.googleapis.com/css?family=Roboto+Slab">

Resource hints en WordPress

A partir de la versión 4.6, WordPress cuenta con un API bastante simple pero, como de costumbre, flexible y extensible para trabajar con resource hints.

Por un lado, la función wp_resource_hints() se encarga de imprimir los resource hints en el <head>. Se ejecuta automáticamente si se incluye wp_head() en el theme.

De forma predeterminada, WordPress imprime un hint tipo dns-prefetch para el dominio s.w.org, que es el CDN de WordPress.org. Pero lo más interesante, es que analiza automáticamente todos los scripts y estilos en cola y se genera un hint tipo dns-prefetch para cada dominio externo que encuentre.

Por ejemplo, si se carga una webfont desde Google:

add_action(' wp_enqueue_scripts', 'cyb_enqueue_scripts' );
function cyb_enqueue_scripts() {
  wp_enqueue_style( 'headings-font', esc_url_raw( 'https://fonts.googleapis.com/css?family=Raleway' ) );
}

WordPress genera de forma automática el siguiente hint:

<link rel='dns-prefetch' href='//fonts.googleapis.com' />

Por otro lado, está disponible el filtro wp_resource_hints. El filtro es ejecutado por cada tipo de rel (actualmente preload no es soportado) y recibe el tipo de rel y todas las URLs o dominios asociados con ese tipo de rel.

apply_filters( 'wp_resource_hints', array( array( $urls ), string $relation_type ) );

Ejemplo: añadir un resource hint tipo prefetch:

add_filter( 'wp_resource_hints', 'cyb_resource_hints', 10, 2 );
function cyb_resource_hints( $hints, $relation_type ) {

  if( 'prefetch' == $relation_type ) {
    $hints[] = 'https://fonts.googleapis.com/css?family=Raleway';
  }

  return $hints;

}

Referencias

  1. Resource Hints. W3C Working Draft. Consultado el 06 de Octubre de 2016.
  2. Preload. W3C Working Draft. Consultado el 06 de Octubre 2016.
  3. Bram Stein. (Au­gust 7, 2015). Preload Hints For Web Fonts.
  4. Pascal Birchler. (6 de Julio de 2016). Resource Hints in 4.6. Make WordPress Core.