DEV Community

Speculation Rules API: Selectores y carga dinámica

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>
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

Vamos analizar directamente el speculation rules object

{
  prerender: [
    {
      where: {
        href_matches: mapHrefByType[user.type],
      },
    },
  ],
};
Enter fullscreen mode Exit fullscreen mode

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:

El prerender no se realizó

¿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

El prerender se hace al hacer un click

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 y where 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',
      },
    ],
  };
}
Enter fullscreen mode Exit fullscreen mode

Ahora si recargas la página veras como el prerender se realiza sin necesidad de una interacción.

Prerender con immediate

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',
      },
    ],
  };
}
Enter fullscreen mode Exit fullscreen mode

Prerender con selector

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)

Collapse
 
aalvarado profile image
aalvarado

Interesante API experimental, gracias por compartir