En un post anterior escribí un poco sobre Speculation Rules API y como podíamos usarla para hacer un prerender de páginas para dar una sensación de navegación instantanea a los usuarios.
En este post vamos a hablar sobre como cargar dinámicamente un script con nuestras Speculation Rules y como usar selectores para seleccionar las páginas a las que queremos hacer prerender. Para ello planteemos el siguiente escenario.
Basados en la analítica de nuestro sitio web, determinamos que los usuarios tipo A, en un 80% de los casos hacen click en el link 1 y los usuarios tipo B, en un 89% de los casos hacen click en link 2.
Al analizar este caso vemos que tenemos un caso concreto donde podemos hacer prerender. Recuerden, el prerender es útil pero también es peligroso ya que al final quieras o no estas consumiento recursos.
Bueno para este caso necesitamos
- Nuestra web (página principal, pagina a la que apunte el link 1 y link 2 respectivamente)
- Un script para cargar nuestras reglas de manera dinámica
Nuestra web
Primero nuestra web, algo simple para evitar mas carga cognitiva de la necesaria
Pagina principal
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Main page</title>
</head>
<body>
<h1>Main page</h1>
<a href="/link1.html" class="link1">Link 1</a>
<br />
<a href="/link2.html" class="link2">Link 2</a>
<script async defer type="application/javascript">
/* Todo nuestro código irá aquí */
</script>
</body>
</html>
Pagina link 1
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Link 1</title>
</head>
<body>
<h1>Link 1</h1>
<a href="/">Back to main page</a>
</body>
</html>
Página link 2
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Link 2</title>
</head>
<body>
<h1>Link 2</h1>
<a href="/">Back to main page</a>
</body>
</html>
Script
Nuestro script tendrá 2 partes primero una función que creará nuestro speculation rules object, este recibirá al usuario para decidir el contenido de la regla y la segunda parte es la que carga el script
function createSpeculationRulesObject(user) {
const mapHrefByType = {
A: '/link1.html',
B: '/link2.html',
};
return {
prerender: [
{
where: {
href_matches: mapHrefByType[user.type],
},
},
],
};
}
function injectSpeculationRules(speculationRulesObject) {
const scriptType = 'speculationrules';
if (HTMLScriptElement.supports && HTMLScriptElement.supports(scriptType)) {
const specScript = document.createElement('script');
specScript.type = scriptType;
specScript.textContent = JSON.stringify(speculationRulesObject);
document.body.append(specScript);
}
}
const user = {
type: 'A',
};
const speculationRulesObject = createSpeculationRulesObject(user);
injectSpeculationRules(speculationRulesObject);
Vamos analizar directamente el speculation rules object
{
prerender: [
{
where: {
href_matches: mapHrefByType[user.type],
},
},
],
};
En ejemplos anteriores usabamos una lista de urls usando la propiedad urls: ["link1", "link2", "etc"]
(doc). En este ejemplo podríamos agregar a la lista la página sin ningún problema. Pero queremos usar la propiedad where
(doc) ya que es más flexible, en este momento usamos la propiedad href_matches
(doc) con la cual se hace el prerender de los elementos que apunten a las urls que hagan match pero también podríamos usar la propiedad selector_matches
(doc). Si ejecutas el ejemplo con un servidor y abres tus devtools en Application veras lo siguiente:
¿Qué es lo que pasó?
Antes de explicar lo que pasó haz lo siguiente, con las devtools abiertas en Speculative loads, ve al enlace link1 y haz un click largo, veras lo siguiente
Ahora si se viene lo chido, el speculation rules object hay una propiedad llamada eagerness
(info aquí). Esta indica cuando debe hacerse el prerender y toma un valor por default dependiendo de que propiedades declare el objeto.
Cuando el objeto define la propiedad urls
el valor por defecto de eagerness será "https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/speculationrules#immediate", lo que quiere decir que el prerender se hará lo más rápido posible.
Cuando el objeto define la propiedad where
el valor por defecto de eagerness será "conservative", lo que quiere decir que el prerender se hará hasta que ocurra un evento como un click sobre el link.
El objeto speculation rule no puede tener la propiedad
urls
ywhere
a la vez
Para este ejemplo queremos que cargue inmediatamente así que definamos eagerness con el valor immediate y cambiemos el usuario que le pasamos con type B (solo para variar). Nota, esta API es muy sensible a typos, así que si te equivocas al definir alguna propiedad dejará de funcionar.
function createSpeculationRulesObject(user) {
const mapHrefByType = {
A: '/link1.html',
B: '/link2.html',
};
return {
prerender: [
{
where: {
href_matches: mapHrefByType[user.type],
},
eagerness: 'immediate',
},
],
};
}
Ahora si recargas la página veras como el prerender se realiza sin necesidad de una interacción.
Para finalizar, vamos a cambiar un poco el script y en lugar de usar urls usaremos selectores.
function createSpeculationRulesObject(user) {
const mapSelectorsByType = {
A: '.link1',
B: '.link2',
};
return {
prerender: [
{
where: {
selector_matches: mapSelectorsByType[user.type],
},
eagerness: 'immediate',
},
],
};
}
Tenemos exactamente el mismo resultado. Como dato extra, si al momento de agregar la regla no hay algún elemento que haga match, no hay ningún problema, en cuanto exista el prerender se ejecutará.
Conclusiones
Puedes usar Speculation Rules API para hacer prerender dinámico basada en la data de tu aplicación. En este caso usamos "immediate" pero en casos de la vida real podemos tomar en cuenta mas factores para hacer la inyección de reglas o incluso usar un eagerness con el valor moderate
(doc) que inicia el render cuando el elemento esta en el viewport y se hace un hover. Si bien podemos cargar una páginas más rápido también hay que ser cuidadosos con el consumo de recursos
Top comments (1)
Interesante API experimental, gracias por compartir