<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Joel Humberto Gómez Paredes</title>
    <description>The latest articles on DEV Community by Joel Humberto Gómez Paredes (@dezkareid).</description>
    <link>https://dev.to/dezkareid</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F461615%2Fb7e9c050-6fa6-4365-b06a-48ceb6c71ea3.jpg</url>
      <title>DEV Community: Joel Humberto Gómez Paredes</title>
      <link>https://dev.to/dezkareid</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dezkareid"/>
    <language>en</language>
    <item>
      <title>Sincronizando mi AGENTS.md</title>
      <dc:creator>Joel Humberto Gómez Paredes</dc:creator>
      <pubDate>Wed, 11 Feb 2026 20:15:35 +0000</pubDate>
      <link>https://dev.to/dezkareid/sincronizando-mi-agentsmd-4e0c</link>
      <guid>https://dev.to/dezkareid/sincronizando-mi-agentsmd-4e0c</guid>
      <description>&lt;p&gt;Una de las cosas mas importantes para el AI Assisted development es el contexto. Este es una forma de darle instrucciones a nuestros agentes para que alucinen lo menos posible y realicen lo que necesitamos.&lt;/p&gt;

&lt;p&gt;Cada agente/asistente/tool tiene su forma de definir un archivo que sea su fuente de la verdad, muchos están adoptando el uso de un archivo especial &lt;a href="https://agents.md/" rel="noopener noreferrer"&gt;AGENTS.md&lt;/a&gt; lo cual es genial porque los estandares son buenos para guiar una industria y darle cierta estabilidad.&lt;/p&gt;

&lt;p&gt;Yo adopte este mindset y si bien hay algunas herramientas que adoptan esto, hay otras que tienen un soporte mixto dan soporte al AGENTS.md pero también a su propio archivo. Peeeeeeero también hay otras herramientas que no lo hacen.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sincronizando contexto
&lt;/h2&gt;

&lt;p&gt;Para resolver este "problema" cree una tool bastante simple (por ahora) llamada &lt;a href="https://github.com/dezkareid/dezkareid/tree/main/packages/ai-context-sync" rel="noopener noreferrer"&gt;@dezkareid/ai-context-sync&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;La cual usa el archivo AGENTS.md como fuente de la verdad y a traves de algunas estrategias configura/enlaza este archivo con el que necesitan algunas herramientas como Claude Code y Gemini CLI.&lt;/p&gt;

&lt;p&gt;Pueden probarla usando npx&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx @dezkareid/ai-context-sync &lt;span class="nb"&gt;sync&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5n778gv4zvdj1t72qqul.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5n778gv4zvdj1t72qqul.png" alt="Menu para seleccionar estrategia: Claude, Gemini CLI, Gemini MD" width="800" height="156"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Dependiendo de la estrategia que selecciones creará un archivo de configuración y así dependiendo de esta configuración puede generar esa sincronización nuevamente.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdd8vp451cirpzw0yp714.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdd8vp451cirpzw0yp714.png" alt="Archivo de configuración con estrategias seleccionadas: Claude y Gemini" width="656" height="382"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Como desarrolladores nunca es recomendable estar atado a una sola herramienta, es por eso estamos constantemente analizando e iterando.&lt;/p&gt;

&lt;p&gt;Durante este pequeño desarrollo agregue soporte para seleccionar alguna estrategia directamente.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx @dezkareid/ai-context-sync &lt;span class="nb"&gt;sync&lt;/span&gt; &lt;span class="nt"&gt;--strategy&lt;/span&gt; claude
npx @dezkareid/ai-context-sync &lt;span class="nb"&gt;sync&lt;/span&gt; &lt;span class="nt"&gt;--strategy&lt;/span&gt; gemini
npx @dezkareid/ai-context-sync &lt;span class="nb"&gt;sync&lt;/span&gt; &lt;span class="nt"&gt;--strategy&lt;/span&gt; all
npx @dezkareid/ai-context-sync &lt;span class="nb"&gt;sync&lt;/span&gt; &lt;span class="nt"&gt;--strategy&lt;/span&gt; &lt;span class="s2"&gt;"claude, gemini"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No es una herramienta que uses muchas veces en tu ciclo de desarrollo o quizás si, no lo se, solo las descargas lo dirán jeje.&lt;/p&gt;

&lt;h2&gt;
  
  
  Motivación
&lt;/h2&gt;

&lt;p&gt;Esto no es un problema que vaya mas allá del copiar y pegar, el "problema" es tener que modificar o mas bien tener contexto de que cosas hay que modificar.&lt;/p&gt;

&lt;p&gt;Tener un markdown para cada herramienta es una pesadilla pero es peor tener información y contexto duplicado.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;El context engineering y el One Piece son reales.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Yo estoy tratando de definir mi estado del arte en AI y también para mis equipos de trabajo, entonces esto fue algo que solucionó mi problema por el momento, así que soy feliz.&lt;/p&gt;

&lt;h2&gt;
  
  
  Futuro
&lt;/h2&gt;

&lt;p&gt;Algunos editores como &lt;a href="https://cursor.com/docs/context/rules#agentsmd" rel="noopener noreferrer"&gt;cursor&lt;/a&gt; y &lt;a href="https://docs.windsurf.com/windsurf/cascade/agents-md" rel="noopener noreferrer"&gt;windsurf&lt;/a&gt; ya incluyen el soporte para AGENTS.md pero no &lt;a href="https://antigravity.google/" rel="noopener noreferrer"&gt;antigravity&lt;/a&gt;, así que probablemente en lo que dan soporte agregaré una regla que permita hacer referencia a este archivo.&lt;/p&gt;

&lt;p&gt;Como dije antes, cada tool puede seleccionar el camino que desee, adoptar un estandar o salir de el para generar algo diferente. Lo hermoso de esta época es que ahora pasamos menos tiempo escribiendo código y mas tiempo diseñandolo.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>softwaredevelopment</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Publicación de paquetes npm turborepo, trusted publisher, pnpm</title>
      <dc:creator>Joel Humberto Gómez Paredes</dc:creator>
      <pubDate>Sat, 07 Feb 2026 22:03:49 +0000</pubDate>
      <link>https://dev.to/dezkareid/publicacion-de-paquetes-npm-turborepo-trusted-publisher-pnpm-18ch</link>
      <guid>https://dev.to/dezkareid/publicacion-de-paquetes-npm-turborepo-trusted-publisher-pnpm-18ch</guid>
      <description>&lt;p&gt;Hace una semana me di a la tarea de hacer un update a mi &lt;a href="https://github.com/dezkareid/dezkareid" rel="noopener noreferrer"&gt;monorepo personal&lt;/a&gt; (aún seguimos trabajando en ello).&lt;/p&gt;

&lt;p&gt;Dentro de todas las tareas tuve que realizar la de publicar paquetes fue de las más complicadas y vengo a explicarles un poco del porque puede ser complejo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Old way
&lt;/h2&gt;

&lt;p&gt;Mi proceso anterior era bastante simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Entrar a &lt;a href="https://npmjs.com/" rel="noopener noreferrer"&gt;npmjs&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Generar un token de acceso.&lt;/li&gt;
&lt;li&gt;Agregar el token a tu proceso de publicación.&lt;/li&gt;
&lt;li&gt;Crear la env var de NPM_TOKEN y el GITHUB_TOKEN a semantic-release.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Y listo, pero se cambiaron ciertas políticas de seguridad en npmjs que ahora sugiere el uso de &lt;a href="https://docs.npmjs.com/trusted-publishers" rel="noopener noreferrer"&gt;trusted publishing&lt;/a&gt; para la publicación usando &lt;a href="https://openid.net/developers/how-connect-works/" rel="noopener noreferrer"&gt;OpenID Connect&lt;/a&gt; en lugar de un token tradicional.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuración de trusted publishing
&lt;/h2&gt;

&lt;p&gt;Antes de crear la configuración del trusted publisher en npmjs, tu paquete debe existir en npmjs si o si.&lt;/p&gt;

&lt;p&gt;En el caso de que vayas a publicar un paquete nuevo, lo que debes hacer es una publicación manual (&lt;code&gt;pnpm publish --tag dummy&lt;/code&gt;) o usar una herramienta llamada &lt;a href="https://github.com/azu/setup-npm-trusted-publish" rel="noopener noreferrer"&gt;setup-npm-trusted-publish&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Ahora debes acceder a la sección de configuración de tu paquete en &lt;code&gt;https://www.npmjs.com/package/&amp;lt;package-name/access&lt;/code&gt; o &lt;code&gt;https://www.npmjs.com/package/&amp;lt;scope&amp;gt;/&amp;lt;package-name/access&lt;/code&gt;. Después debes agregar los datos de tu trusted publisher (github o gitlab).&lt;/p&gt;

&lt;p&gt;Debe aparecerte algo similar a esto:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4y6cwq9pwq5gs26av9gp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4y6cwq9pwq5gs26av9gp.png" alt="Seleccionando trusted publisher" width="800" height="272"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Una vez seleccionado solo hay que llenar datos:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Organización o usuario&lt;/li&gt;
&lt;li&gt;Repositorio&lt;/li&gt;
&lt;li&gt;Nombre del archivo de tu workfflow (incluyendo extensión). &lt;em&gt;Nota: este debe estar dentro de tu folder de .github/workflows&lt;/em&gt; .&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frrzrwzbkhdr74cldgnjr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frrzrwzbkhdr74cldgnjr.png" alt="Form de trusted publisher" width="800" height="582"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;En mi caso fue:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;dezkareid&lt;/li&gt;
&lt;li&gt;dezkareid&lt;/li&gt;
&lt;li&gt;ci-packages.yml&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Listo ya la configuración esta completa, ahora hay que realizar la configuración de nuestro publisher en nuestro workflow.&lt;/p&gt;
&lt;h2&gt;
  
  
  Configuración de trusted publishing en Github Action
&lt;/h2&gt;

&lt;p&gt;Lo primero que necesitamos es configurar los permisos en nuestro job&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;id-token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Estrictamente solo necesitamos el permiso de id-token para la conexión usando OpenID Connect y podríamos usar npm publish, pero como uso semantic-release para subir el tag a github y el changelog, entre otras cosas. Mi configuración es la siguiente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt;
  &lt;span class="na"&gt;issues&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt;
  &lt;span class="na"&gt;pull-requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt;
  &lt;span class="na"&gt;id-token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aquí hay un &lt;a href="https://semantic-release.gitbook.io/semantic-release/recipes/ci-configurations/github-actions#github-workflows-release.yml-configuration-for-node-projects" rel="noopener noreferrer"&gt;ejemplo de un action&lt;/a&gt; que usa esta configuración.&lt;/p&gt;

&lt;p&gt;Mi configuración de semantic-release&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"plugins"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"@semantic-release/commit-analyzer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"@semantic-release/release-notes-generator"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"@semantic-release/changelog"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"@semantic-release/npm"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"@semantic-release/git"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"assets"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="s2"&gt;"CHANGELOG.md"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"@semantic-release/github"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En esta parte tuve algunos problemas debido a mi arquitectura y a mi stack.&lt;/p&gt;

&lt;p&gt;Yo uso una arquitectura de monorepo y no de polirepo, eso agrega complejidad ya que debes ubicarte especificamente en el proyecto que debes publicar. Ademas de que estoy usando pnpm entonces ocurrió algo raro que me pedía autenticarme. Al ser un monorepo uso workspaces y no de manejan de la misma manera usando npm que pnmp.&lt;/p&gt;

&lt;p&gt;Entre los problemas que enfrente fueron los siguientes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Capa 8, no agregué correctamente el nombre del archivo de mi workflow, me di cuenta de esto porque al tratar de publicar el plugin de npm verifica si el OpenID connect esta bien configurado y me decía que no encontraba la configuración.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Tenía un comando release usando que era ejecutado directamente por &lt;a href="https://turborepo.dev/" rel="noopener noreferrer"&gt;turborepo&lt;/a&gt;, el problema es que este aplica un filtro de variables de entorno y debes indicar explicitamente cuales necesitas. Lo solucioné usando el folder con el cambio como working directory y ejecutando semantic-release directamente&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;El &lt;a href="https://github.com/semantic-release/npm" rel="noopener noreferrer"&gt;plugin de semantic release de npm&lt;/a&gt; no estaba funcionando, el problema no era el plugin sino mi stack. Al parecer había un detalle de como se manejaba la autenticación, la documentación de las herramientas por lo regular contempla que estes usando npm pero a bajo nivel puede ser que aunque tengas una herramienta que funcione de manera similar no siempre va a funcionar con tu stack. La solución fue instalar el plugin &lt;a href="https://www.npmjs.com/package/@anolilab/semantic-release-pnpm" rel="noopener noreferrer"&gt;@anolilab/semantic-release-pnpm&lt;/a&gt;. &lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Mi configuración quedó de la siguiente manera&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;plugins"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;
    &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;@semantic-release/commit-analyzer"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;@semantic-release/release-notes-generator"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;@semantic-release/changelog"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;@anolilab/semantic-release-pnpm"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
    &lt;span class="pi"&gt;[&lt;/span&gt;
      &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;@semantic-release/git"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
      &lt;span class="pi"&gt;{&lt;/span&gt;
        &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;assets"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;
          &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CHANGELOG.md"&lt;/span&gt;
        &lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="pi"&gt;}&lt;/span&gt;
    &lt;span class="pi"&gt;],&lt;/span&gt;
    &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;@semantic-release/github"&lt;/span&gt;
  &lt;span class="pi"&gt;],&lt;/span&gt;
  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;extends"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;semantic-release-monorepo"&lt;/span&gt;
&lt;span class="pi"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Y con esto ahora ya puedo publicar paquetes nuevamente usando mi stack preferido. Te dejo mi &lt;a href="https://github.com/dezkareid/dezkareid/blob/main/.github/workflows/ci-packages.yml" rel="noopener noreferrer"&gt;workflow&lt;/a&gt; para que puedas observarlo y si te sirve lo puedas replicar :D&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>programming</category>
    </item>
    <item>
      <title>Textos y fragmentos contenido relevante en tu web</title>
      <dc:creator>Joel Humberto Gómez Paredes</dc:creator>
      <pubDate>Sat, 04 Oct 2025 23:30:31 +0000</pubDate>
      <link>https://dev.to/dezkareid/textos-y-fragmentos-contenido-relevante-en-tu-web-5h80</link>
      <guid>https://dev.to/dezkareid/textos-y-fragmentos-contenido-relevante-en-tu-web-5h80</guid>
      <description>&lt;p&gt;Uno de los atributos mas importantes para tu web es el "discoverability" por esto me refiero a como el usuario encuentra tu producto. En este caso me enfocaré en la web. Hay muchos medios por el cual el usuario encuentra tu web pero sin duda alguna mucho de ese tráfico será mediante el buscador.&lt;/p&gt;

&lt;p&gt;Mediante el Search Engine Optimization (SEO) podemos hacer modificaciones a nuestra web para incrementar nuestro ranking y sobresalir entre otras opciones (competencia).&lt;/p&gt;

&lt;p&gt;Hay muchas formas de optimizar pero en este post me enfocaré en el contenido y una parte que casi no he visto que se aborde son los fragmentos de texto (&lt;a href="https://developer.mozilla.org/en-US/docs/Web/URI/Reference/Fragment/Text_fragments" rel="noopener noreferrer"&gt;text fragments&lt;/a&gt;).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;En el mundo de la web, el contenido es el rey&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://web.dev/articles/url-parts" rel="noopener noreferrer"&gt;De las partes que forman una URL&lt;/a&gt; sin duda alguna hemos visto fragmentos pero seguramente no hemos usado fragmentos de texto.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Un fragmento de texto nos permite compartir un link hacia nuestro contenido, que el navegador haga scroll hacia el fragmento y que se aplique un highlight para que el usuario pueda visualizarlo.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/URI/Reference/Fragment/Text_fragments#:~:text=Text%20fragments%20are%20a%20kind%20of%20URL%20fragment%2C%20and%20is%20written%20after%20the%20%23" rel="noopener noreferrer"&gt;Fuente&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Porqué es importante?
&lt;/h2&gt;

&lt;p&gt;Permite que el usuario encuentre lo que busca de manera rápida, incluso los buscadores ofrecen esos fragmentos como referencia y también nos da la posibilidad de priorizar el contenido mas relevante dentro de nuestra web si queremos hacer difusión.&lt;/p&gt;

&lt;p&gt;Esta feature esta definida en los &lt;a href="https://wicg.github.io/scroll-to-text-fragment/" rel="noopener noreferrer"&gt;estándares web de la comunidad&lt;/a&gt; por si quieren darle un vistazo :)&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Cómo la uso?
&lt;/h2&gt;

&lt;p&gt;Primero analicemos la sintaxis&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://example.com#:~:text=[prefix-,]textStart[,textEnd][,-suffix]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En la URL observamos que después del símbolo de hash &lt;code&gt;#&lt;/code&gt; se encuentran los siguientes simbolos &lt;code&gt;:~:&lt;/code&gt;, a esto se le conoce como fragment directive. Esta directiva le dice al browser que debe buscar una secuencia de texto (básicamente es como un CTRL + F o Command + F).&lt;/p&gt;

&lt;p&gt;La directiva de texto &lt;code&gt;text=&lt;/code&gt; nos indica el fragmento de texto que se va a buscar. Una nota importante es que el texto a buscar debe esta &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent" rel="noopener noreferrer"&gt;codíficado&lt;/a&gt; para que se pueda buscar.&lt;/p&gt;

&lt;p&gt;La forma más simple de utilizar un fragmento de texto es: codificar un texto y agregalo después de la directiva. &lt;a href="https://developer.mozilla.org/en-US/docs/Web/URI/Reference/Fragment/Text_fragments#:~:text=Text%20fragments%20are%20a%20kind%20of%20URL%20fragment%2C%20and%20is%20written%20after%20the%20%23" rel="noopener noreferrer"&gt;Ejemplo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Anteriormente te había dicho que es como un &lt;code&gt;CTRL + F&lt;/code&gt; o &lt;code&gt;Command + F&lt;/code&gt; pero podemos agregar como debe terminar el fragmento de texto, hasta prefijos y sufijos (ambos opcionales).&lt;/p&gt;

&lt;p&gt;Voy a usar como ejemplo el siguiente &lt;a href="https://codepen.io/dezkareid/pen/XJXpXaJ" rel="noopener noreferrer"&gt;codePen&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cuando solo usamos &lt;code&gt;#:~:text=texto&lt;/code&gt; solo buscará ese texto  &lt;a href="https://codepen.io/dezkareid/pen/XJXpXaJ#:~:text=texto" rel="noopener noreferrer"&gt;observen&lt;/a&gt;. &lt;strong&gt;Por cierto, esto no funciona en iframes y si no hace hightlight puede ser que algún input este robando foco.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Si agregamos la palabra "anterior":&lt;/p&gt;

&lt;p&gt;&lt;code&gt;https://codepen.io/dezkareid/pen/XJXpXaJ#:~:text=texto,anterior&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Veremos como selecciona mas de una línea porque le indicamos que el fragmento de texto debe iniciar y terminar.&lt;/p&gt;

&lt;p&gt;Si queremos agregar un prefijo lo único que debemos hacer es agregarlo al principio del valor de la directiva seguido de un dash &lt;code&gt;-&lt;/code&gt;, aquí yo estoy usando la palabra prefijo:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;https://codepen.io/dezkareid/pen/XJXpXaJ#:~:text=prefijo-,texto,anterior&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;En este ejemplo notarás que el prefijo no se selecciona, esto es porque se usa como criterio de búsqueda pero lo que define la selección.&lt;/p&gt;

&lt;p&gt;Si queremos usar un posfijo sería muy similar al prefijo pero este debe ir al final y el dash se pone al principio del texto.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;https://codepen.io/dezkareid/pen/XJXpXaJ#:~:text=texto,anterior,-posfijo&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Adicionalmente si quieren agregar estilos custom a la selección pueden usar el pseudo-selector &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/::target-text" rel="noopener noreferrer"&gt;::target-text&lt;/a&gt;. Este esta disponible según Baseline desde el 2024.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dónde puedo usarla
&lt;/h2&gt;

&lt;p&gt;Contenidos como blogposts y artículos son ideales porque quieres transmitir una idea principal, algo que aporta valor y que si bien se puede actualizar o "cambiar", normalmente el cambio son correcciones o nuevos aportes.&lt;/p&gt;

&lt;p&gt;No deberías usar esto en contenido que cambia constantemente porque si el contenido cambia el link deja de ser útil.&lt;/p&gt;

&lt;p&gt;Hay que ser cuidadosos con estos links y no usarlos para todo porque se puede volver inmantenibles en contenido que cambia constantemente.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusiones
&lt;/h2&gt;

&lt;p&gt;Esta feature es algo simple pero que puede apoyar a tener mejor discoverability de su contenido, ya sean en sus estrategias de tráfico orgánico, marketing, campañas, etc. Ya que permite que sus usuarios encuentren el contenido que ustedes quieren que destaque.&lt;/p&gt;

&lt;p&gt;Espero les haya gustado y lo compartan :D&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>seo</category>
    </item>
    <item>
      <title>Cargando imágenes responsive con CSS</title>
      <dc:creator>Joel Humberto Gómez Paredes</dc:creator>
      <pubDate>Wed, 01 Oct 2025 20:05:51 +0000</pubDate>
      <link>https://dev.to/dezkareid/cargando-imagenes-responsive-con-css-5bkk</link>
      <guid>https://dev.to/dezkareid/cargando-imagenes-responsive-con-css-5bkk</guid>
      <description>&lt;p&gt;Uno de los recursos más usados en la web son las imágenes, hay muchas estrategias para cargar imágenes de manera eficiente, en esta ocasión voy a mostrarles una alternativa que no he visto.&lt;/p&gt;

&lt;h2&gt;
  
  
  Imágenes responsivas con srcset
&lt;/h2&gt;

&lt;p&gt;Una de las formas más fáciles de cargar imágenes responsive es el atributo &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/srcset" rel="noopener noreferrer"&gt;srcset&lt;/a&gt; el cual nos permite agregar una imagen dependiendo del tipo de resolución.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;image&lt;/span&gt;
  &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"360px"&lt;/span&gt;
  &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"360px"&lt;/span&gt;
  &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://images.wikidexcdn.net/mwuploads/wikidex/thumb/4/43/latest/20190406170624/Bulbasaur.png/400px-Bulbasaur.png"&lt;/span&gt;
  &lt;span class="na"&gt;srcset=&lt;/span&gt;&lt;span class="s"&gt;"https://images.wikidexcdn.net/mwuploads/wikidex/thumb/4/43/latest/20190406170624/Bulbasaur.png/800px-Bulbasaur.png 2x"&lt;/span&gt;

&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;&lt;strong&gt;Gracias wikidex :3&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;En este ejemplo el browser cargará automaticamente la imagen que mejor se adapte a las condiciones del browser actual, en el caso que nuestra pantalla tenga el &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/Device_pixel" rel="noopener noreferrer"&gt;device pixel&lt;/a&gt; de 2, se cargará el &lt;code&gt;srcset&lt;/code&gt; y en caso contrario se cargará el &lt;code&gt;src&lt;/code&gt; normal.&lt;/p&gt;

&lt;p&gt;Como nota, también podríamos utilizar esta sintaxis y visualmente resultaría lo mismo&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;
&lt;span class="nt"&gt;&amp;lt;image&lt;/span&gt;
  &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"360px"&lt;/span&gt;
  &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"360px"&lt;/span&gt;
  &lt;span class="na"&gt;srcset=&lt;/span&gt;&lt;span class="s"&gt;"https://images.wikidexcdn.net/mwuploads/wikidex/thumb/4/43/latest/20190406170624/Bulbasaur.png/400px-Bulbasaur.png 360w https://images.wikidexcdn.net/mwuploads/wikidex/thumb/4/43/latest/20190406170624/Bulbasaur.png/800px-Bulbasaur.png 800w"&lt;/span&gt;
&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hay 3 posibles detalles con esta estrategia:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;No tenemos un control explícito de que imagen se carga para ciertas condiciones mas allá de la resolución.&lt;/li&gt;
&lt;li&gt;La resolución esta definida no por el tamaño del elemento sino el de la pantalla&lt;/li&gt;
&lt;li&gt;La sintaxis puede ser un poco compleja de entender&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;En un caso de uso que tuve necesitaba cargar una imagen pero solo en resoluciones tablet hacia arriba (vamos a decir que 800px), en mobile no debía mostrarse y por ende tampoco descargarse.&lt;/p&gt;

&lt;p&gt;Para este caso &lt;code&gt;srcset&lt;/code&gt; no me resultaba ideal porque haga lo que haga siempre se descargará una imagen, también se puede utilizar JS para ver si el dispositivo es mobile y en ese caso no agregar el atributo &lt;code&gt;srcset&lt;/code&gt; a la imagen.&lt;/p&gt;

&lt;p&gt;Hay muchas alternativas pero no me convencia mucho el uso de JS para este tipo de escenarios, así que pensé en usar CSS y custom properties.&lt;/p&gt;

&lt;h2&gt;
  
  
  Imágenes responsive con custom properties
&lt;/h2&gt;

&lt;p&gt;En mi caso la imagen era mas que nada un elemento decorativo que descriptivo no tenía problemas con la accesibilidad. Lo cual podría mitigar con aria attributes pero siempre es mejor usar lo nativo que tratar de ser muy listo.&lt;/p&gt;

&lt;p&gt;La clave para decidir usar este approach es que cuando usamos una imagen como background en CSS  y lo combinamos con &lt;code&gt;display: none&lt;/code&gt; la imagen no se descarga (que trucazo).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Esta alternativa no es una propuesta para que se use siempre, a mi me funcionó para mi caso de uso&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;El HTML es el siguiente&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;section&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt;
    &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"image image-responsive"&lt;/span&gt;
    &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"
      --bg-image: url('https://images.wikidexcdn.net/mwuploads/wikidex/thumb/5/56/latest/20200307023245/Charmander.png/800px-Charmander.png');
    "&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;image&lt;/span&gt;
    &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"image"&lt;/span&gt;
    &lt;span class="na"&gt;srcset=&lt;/span&gt;&lt;span class="s"&gt;"https://images.wikidexcdn.net/mwuploads/wikidex/thumb/4/43/latest/20190406170624/Bulbasaur.png/400px-Bulbasaur.png 360w, https://images.wikidexcdn.net/mwuploads/wikidex/thumb/4/43/latest/20190406170624/Bulbasaur.png/800px-Bulbasaur.png 800w"&lt;/span&gt;
  &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/section&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Y el CSS&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;section&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.image&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;300px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;300px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.image-responsive&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--bg-image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;background-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;cover&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="err"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;800px&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.image&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;block&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;En el &lt;code&gt;srcset&lt;/code&gt; cargué 2 imágenes, aunque solo nos interesa la segunda la primera es mas que nada para mostrar la sintaxis de &lt;code&gt;srcset&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Recomiendo mirar el código y después ir al &lt;a href="https://codepen.io/dezkareid/full/jEWMMGO" rel="noopener noreferrer"&gt;pen que cree&lt;/a&gt;, si estas en una resolución menor a 800px no verás nada pero en caso contrario verás a un charmander y a un bulbasaur.&lt;/p&gt;

&lt;p&gt;Abre las devtools, pon el tab de network, filtra los request para solo mostrar los de imagen, haces un resize de pantalla a 360px y recarga. Si hicieste esto y revisas en las imágenes que se descargaron podrás ver que la imagen de bulbasaur se descarga pero no la de charmander.&lt;/p&gt;

&lt;p&gt;Aunque en cierto aspecto la legibilidad de este approach no es muy buena ya que agregar custom properties directamente en el elemento y no a traves de una clase agrega mucho texto y es muy delicado en la parte del setup, ya que &lt;code&gt;srcset&lt;/code&gt; es la solución ideal para el manejo de imágenes responsive. Pero también nos permite tener mayor claridad de que imagen se va a cargar ya que podrías tener varias custom properties para cargarse en escenarios como landscape o dark sin necesidad de usar JS.&lt;/p&gt;

&lt;p&gt;Otro punto a favor o en contra (dependiendo de como lo veas) es que si haces un resize de pantalla se cargaran otras imágenes que hayas definido, dependiendo de la resolución ya que css es reactivo. Puede que quieras eso o no, con &lt;code&gt;srcset&lt;/code&gt; solo se carga la primera imagen seleccionada de acuerdo al criterio definido así que no importa si se hace mas grande la pantalla o mas chica, solo se usará la que se descargó en un inicio.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>performance</category>
      <category>webperf</category>
    </item>
    <item>
      <title>Speculation Rules API: Selectores y carga dinámica</title>
      <dc:creator>Joel Humberto Gómez Paredes</dc:creator>
      <pubDate>Sun, 07 Jul 2024 08:50:53 +0000</pubDate>
      <link>https://dev.to/dezkareid/speculation-rules-api-selectores-y-carga-dinamica-4il8</link>
      <guid>https://dev.to/dezkareid/speculation-rules-api-selectores-y-carga-dinamica-4il8</guid>
      <description>&lt;p&gt;En un &lt;a href="https://dev.to/dezkareid/instant-navigation-con-speculation-rules-api-1dnc"&gt;post anterior&lt;/a&gt; escribí un poco sobre &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Speculation_Rules_API" rel="noopener noreferrer"&gt;Speculation Rules API&lt;/a&gt; y como podíamos usarla para hacer un prerender de páginas para dar una sensación de navegación instantanea a los usuarios.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;Bueno para este caso necesitamos&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Nuestra web (página principal, pagina a la que apunte el link 1 y link 2 respectivamente)&lt;/li&gt;
&lt;li&gt;Un script para cargar nuestras reglas de manera dinámica&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Nuestra web
&lt;/h2&gt;

&lt;p&gt;Primero nuestra web, algo simple para evitar mas carga cognitiva de la necesaria&lt;/p&gt;

&lt;p&gt;Pagina principal&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Main page&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Main page&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/link1.html"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"link1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Link 1&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;br&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/link2.html"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"link2"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Link 2&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;async&lt;/span&gt; &lt;span class="na"&gt;defer&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"application/javascript"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="cm"&gt;/* Todo nuestro código irá aquí */&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pagina link 1&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Link 1&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Link 1&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Back to main page&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Página link 2&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Link 2&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Link 2&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Back to main page&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Script
&lt;/h2&gt;

&lt;p&gt;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&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createSpeculationRulesObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mapHrefByType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;A&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/link1.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;B&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/link2.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;prerender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;href_matches&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;mapHrefByType&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;injectSpeculationRules&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;speculationRulesObject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;scriptType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;speculationrules&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;HTMLScriptElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;supports&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;HTMLScriptElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;supports&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scriptType&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;specScript&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;script&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;specScript&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;scriptType&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;specScript&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;speculationRulesObject&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;specScript&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;A&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;speculationRulesObject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createSpeculationRulesObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;injectSpeculationRules&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;speculationRulesObject&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Vamos analizar directamente el speculation rules object&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;prerender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;href_matches&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;mapHrefByType&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En ejemplos anteriores usabamos una lista de urls usando la propiedad &lt;code&gt;urls: ["link1", "link2", "etc"]&lt;/code&gt;(&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/speculationrules#urls" rel="noopener noreferrer"&gt;doc&lt;/a&gt;). En este ejemplo podríamos agregar a la lista la página sin ningún problema. Pero queremos usar la propiedad &lt;code&gt;where&lt;/code&gt;(&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/speculationrules#where" rel="noopener noreferrer"&gt;doc&lt;/a&gt;) ya que es más flexible, en este momento usamos la propiedad &lt;code&gt;href_matches&lt;/code&gt;(&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/speculationrules#href_matches" rel="noopener noreferrer"&gt;doc&lt;/a&gt;) 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 &lt;code&gt;selector_matches&lt;/code&gt;(&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/speculationrules#selector_matches" rel="noopener noreferrer"&gt;doc&lt;/a&gt;). Si ejecutas el ejemplo con un servidor y abres tus devtools en Application veras lo siguiente:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frrdgea331gi6yd0x2ze0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frrdgea331gi6yd0x2ze0.png" alt="El prerender no se realizó" width="800" height="620"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;¿Qué es lo que pasó?&lt;/p&gt;

&lt;p&gt;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&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxt0o4bn8q0lluzxi7dmg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxt0o4bn8q0lluzxi7dmg.png" alt="El prerender se hace al hacer un click" width="800" height="754"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ahora si se viene lo chido, el speculation rules object hay una propiedad llamada &lt;code&gt;eagerness&lt;/code&gt; (&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/speculationrules#eagerness" rel="noopener noreferrer"&gt;info aquí&lt;/a&gt;). Esta indica cuando debe hacerse el prerender y toma un valor por default dependiendo de que propiedades declare el objeto.&lt;/p&gt;

&lt;p&gt;Cuando el objeto define la propiedad &lt;code&gt;urls&lt;/code&gt; el valor por defecto de eagerness será "&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/speculationrules#immediate" rel="noopener noreferrer"&gt;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/speculationrules#immediate&lt;/a&gt;", lo que quiere decir que el prerender se hará lo más rápido posible.&lt;/p&gt;

&lt;p&gt;Cuando el objeto define la propiedad &lt;code&gt;where&lt;/code&gt; el valor por defecto de eagerness será "&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/speculationrules#conservative" rel="noopener noreferrer"&gt;conservative&lt;/a&gt;", lo que quiere decir que el prerender se hará hasta que ocurra un evento como un click sobre el link.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;El objeto speculation rule no puede tener la propiedad &lt;code&gt;urls&lt;/code&gt; y &lt;code&gt;where&lt;/code&gt; a la vez&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;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.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createSpeculationRulesObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mapHrefByType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;A&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/link1.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;B&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/link2.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;prerender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;href_matches&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;mapHrefByType&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;eagerness&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;immediate&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fytsfx91ymvgwqytwn9cy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fytsfx91ymvgwqytwn9cy.png" alt="Prerender con immediate" width="800" height="818"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Para finalizar, vamos a cambiar un poco el script y en lugar de usar urls usaremos selectores.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createSpeculationRulesObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mapSelectorsByType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;A&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.link1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;B&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.link2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;prerender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;selector_matches&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;mapSelectorsByType&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;eagerness&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;immediate&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8m7kygi0qlk96zp0hyj3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8m7kygi0qlk96zp0hyj3.png" alt="Prerender con selector" width="800" height="587"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;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á.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusiones
&lt;/h2&gt;

&lt;p&gt;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 &lt;code&gt;moderate&lt;/code&gt; (&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/speculationrules#moderate" rel="noopener noreferrer"&gt;doc&lt;/a&gt;) 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&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>webperf</category>
    </item>
    <item>
      <title>Instant Navigation con Speculation Rules API</title>
      <dc:creator>Joel Humberto Gómez Paredes</dc:creator>
      <pubDate>Wed, 26 Jun 2024 05:54:45 +0000</pubDate>
      <link>https://dev.to/dezkareid/instant-navigation-con-speculation-rules-api-1dnc</link>
      <guid>https://dev.to/dezkareid/instant-navigation-con-speculation-rules-api-1dnc</guid>
      <description>&lt;p&gt;Uno de las fantasías de todo frontend es que la navegación entre las diferentes partes de nuestra web sea instantanea como si de alguna manera la web estuviera lista para la página a la que queremos acceder.&lt;/p&gt;

&lt;p&gt;El browser nos ofrece mecanismos como los &lt;a href="https://web.dev/learn/performance/resource-hints" rel="noopener noreferrer"&gt;resource hints&lt;/a&gt; para poder hacer precargas (entre los mas conocidos preload y prefetch) de recursos lo cual nos da la posibilidad de reducir tiempos de carga.&lt;/p&gt;

&lt;p&gt;Antes de tenía un resource hint llamado prerender pero fue eliminado por múltiples bugs pero ahora regreso en forma de ficha con la &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Speculation_Rules_API" rel="noopener noreferrer"&gt;Speculation Rules API&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Speculation Rules API
&lt;/h2&gt;

&lt;p&gt;Antes de empezar, una aclaración preload y prefetch sirven para hacer el request de recursos para que cuando se usen ya se hayan descargado (Hay mas diferencias pero quiero simplificar). Esto en archivos de assets esta perfecto pero cuando se solicitan documentos HTML estos solo se renderizarán cuando ese documento se cargue en el contexto del browser.&lt;/p&gt;

&lt;p&gt;Si quisieramos cargar algún recurso preload y prefetch son suficientes, esto normalmente tiene mayor uso en una Single Page App (SPA), en una SPA la navegación es mas compleja porque todo se administra dentro del contexto de la aplicación. Cuando tenemos una Multi Page App (MPA) donde la navegación es simple pero se cambia todo el contexto de la aplicación. Aquí es donde Speculation Rules API nos permite especificar que URLs podemos &lt;a href="https://developer.chrome.com/docs/web-platform/prerender-pages" rel="noopener noreferrer"&gt;prerenderizar&lt;/a&gt; para darnos una sensación de inmediates.&lt;/p&gt;

&lt;h3&gt;
  
  
  Advertencia
&lt;/h3&gt;

&lt;p&gt;La implementación de Speculation Rules API también tiene consecuencias, al hacer un prerender nuestro JS se ejecuta. Si tenemos analytics podemos estar introduciendo ruido a nuestras métricas ya que estamos "Especulando" ya que nada nos garantiza que el usuario va a acceder a las urls que especificamos.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Adicionalmente sería bueno considerar el tipo de dispositivo y conexión&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Demo
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiqrejva0dthy6qlyeruu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiqrejva0dthy6qlyeruu.png" alt="Sitio web con links a page2 y page3" width="800" height="589"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cree un sitio sencillo con 3 páginas: index, page2 y page3 (que creativo).&lt;/p&gt;

&lt;p&gt;El servidor que cree para servir el contenido hace que cualquier URL que termine en .html tendrá un delay de 2 segundos (Esta parte es opcional y se hizo por motivos dramáticos XD)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;path&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;9000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Define the static files directory&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;staticPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;public&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Middleware to delay response for HTML files&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;endsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.html&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Delay by 2 seconds&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Serve static files&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;static&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;staticPath&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Server listening on port &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Código Page2&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Page 2&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Page 2&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Código Page3&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Page 3&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Page 3&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Código index.html&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Main&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"speculationrules"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;prerender&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;urls&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;page2.html&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Speculation API&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"page2.html"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Page 2&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"page3.html"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Page 3&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;La Speculation Rules API puede ser usada como un tipo de script o también como un JSON externo pero este debe ser especificado en un Header.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Speculation Rules API no es un API que pueda usarse directamente con JS, funciona como un JSON donde especificas una configuración.&lt;/p&gt;

&lt;p&gt;Si usas Chrome, antes de ejecutar el demo te sugiero abrir las developer tools, ve a Application y busca en el panel izquierdo una sección llamada "Speculative loads". Ahí podras ver que la página se cargó (aunque igual podrías usar Network).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzbtjg8o5nn1ow8nvae52.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzbtjg8o5nn1ow8nvae52.png" alt="Speculative loads" width="800" height="733"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Da click en Page 3 y después a Page 2. ¿Ves la diferencia? Ahora si, vamos a explicar al responsable de lo que acaba de suceder.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"speculationrules"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;prerender&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;urls&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;page2.html&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En la &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Speculation_Rules_API" rel="noopener noreferrer"&gt;referencia de Speculation Rules API&lt;/a&gt; nos especifíca que la configuración es un objeto con 2 propiedades &lt;code&gt;prerender&lt;/code&gt; y &lt;code&gt;prefetch&lt;/code&gt;. Por ahora nos enfocaremos en &lt;code&gt;prerender&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;De acuerdo a la &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/speculationrules" rel="noopener noreferrer"&gt;documentación&lt;/a&gt; las reglas que usamos tienen propiedades como urls, un arreglo donde ponemos las URLs que queremos prerenderizar.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;También existe la propiedad where para hacer una selección mas avanzada de aquello que queremos prerenderizar (lo abordaremos en otros posts)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Hay una propiedad llamada &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/speculationrules#eagerness" rel="noopener noreferrer"&gt;eagerness&lt;/a&gt; que le indica al browser "cuando" se debería hacer el prefetch/prerender de los recursos especificados en la regla.&lt;/p&gt;

&lt;p&gt;Por defecto para lo especificado en "urls", el eagerness tiene un valor de "immediate". Lo que quiere decir que el prerendering comenzará tan pronto como sea posible. Prueba agregando esa propiedad con el valor de "moderate" (no olvides abrir las devtools para ver que sucede)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"speculationrules"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;prerender&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;urls&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;page2.html&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;eagerness&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;moderate&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Te dirá que hay una regla que no se ha disparado&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmk2m9fu2veiw1hq7eev0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmk2m9fu2veiw1hq7eev0.png" alt="Devtools speculation rules" width="800" height="467"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ahora pon el cursor sobre el link y veras como se dispara el evento y hace el prerender. Esto es muy util para evitar prerenders innecesarios.&lt;/p&gt;

&lt;p&gt;En futuros post abordaremos mas sobre los diferentes tipos de eagerness. Nota: tu no tienes forma de saber cuando ocurriran estos eventos de manera exacta, eso lo decide el browser.&lt;/p&gt;

&lt;h2&gt;
  
  
  Consideraciones
&lt;/h2&gt;

&lt;p&gt;Tu script de analytics y ejecución de ciertos scripts que se deben ejecutar únicamente cuando el usuario visite el documento tendrá que tener código adicional.&lt;/p&gt;

&lt;p&gt;Mira el siguiente código rob...inspirado en la documentación de Mozilla&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prerendering&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;prerenderingchange&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;initAnalytics&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;once&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;initAnalytics&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Si bien el API no puede ser usada directamente con JS, puedes usar JS para agregarlas dinámicamente&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;HTMLScriptElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;supports&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
  &lt;span class="nx"&gt;HTMLScriptElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;supports&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;speculationrules&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;specScript&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;script&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;specScript&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;speculationrules&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;specRules&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;prefetch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;list&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;urls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/next.html&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="nx"&gt;specScript&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;specRules&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;specScript&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Habrá mas post, sobre esta API en el futuro, integraciones con react y como usarla en producción sin preocupaciones aunque esta API sea experimental.&lt;/p&gt;

&lt;p&gt;Si les gusta compartan, sino pues también XD. Nos vemos en futuros posts&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>webperf</category>
      <category>javascript</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Persistencia para frontends</title>
      <dc:creator>Joel Humberto Gómez Paredes</dc:creator>
      <pubDate>Mon, 24 Jun 2024 07:39:21 +0000</pubDate>
      <link>https://dev.to/dezkareid/persistencia-para-frontends-2b64</link>
      <guid>https://dev.to/dezkareid/persistencia-para-frontends-2b64</guid>
      <description>&lt;p&gt;Uno de los mitos en el desarrollo web es que los developers especializados en frontend es que en su trabajo no involucra la construcción de bases de datos, solo consultas a APIs.&lt;/p&gt;

&lt;p&gt;Nada mas lejos de la verdad, si bien la fuente de la verdad absoluta siempre serán los datos provenientes de una API. La data de los endpoints por si sola no tiene significados hasta que no la estructuramos y la usamos.&lt;/p&gt;

&lt;p&gt;Cuando definimos el estado de una aplicación, estructuramos data de modo que la UI puede mostrar información y/o ciertas acciones pueden ser permitidas o negadas.&lt;/p&gt;

&lt;p&gt;Otro escenario es cuando queremos que cierta data persista pero solo en el navegador. ¿Porqué no todo en el server? Bueno crear/mantener un endpoint involucra un costo y hay veces que la persistencia que se busca no requiere de un servidor (ejemplo: un token de autenticación).&lt;/p&gt;

&lt;p&gt;Bueno continuamos, normalmente la data del estado de una aplicación esta in-memory y cuando abrimos otra tab, tiene su propio stack de memoria donde la data no se comparte.&lt;/p&gt;

&lt;p&gt;El browser tiene varios mecanismos de storage: LocalStorage, SessionStorage, Cache API, IndexedDB, etc. Cada uno tiene un propósito pero por el momento no ahondaremos en eso, me enfocaré en que estos nos ofrecen persistencia a nivel dominio, lo cual es útil para poder tener datos que sean consistentes en todas la tabs abiertas en nuestra web en un navegador y en algunos casos poder hacer sincronización de datos con el servidor cuando por alguna razón perdemos la conexión o estamos en modo "offline".&lt;/p&gt;

&lt;h2&gt;
  
  
  Consideraciones
&lt;/h2&gt;

&lt;p&gt;Ya vimos que tenemos varios storages para persistir datos, ¿y?. La persistencia en el browser involucra ciertas consideraciones que hay que tomar en cuenta para la estabilidad y el buen funcionamiento de nuestra web&lt;/p&gt;

&lt;h3&gt;
  
  
  Persistencia temporal
&lt;/h3&gt;

&lt;p&gt;La data del browser (storage) puede ser borrada ya sea por el mismo browser o por el usuario. Esta consideración nos agrega un constraint.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;En ningún momento des por hecho que va a existir data&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Hay data que corresponde a operaciones sensibles, como un flujo de pagos que es preferible manejar la persistencia a nivel servidor y quizas solo persistir en el browser el resultado final porque la data podría ser borrada en cualquier momento, cosa que no pasaría en una base de datos en el servidor.&lt;/p&gt;

&lt;h3&gt;
  
  
  Limites y permisos
&lt;/h3&gt;

&lt;p&gt;Si bien los equipos de computo tienen cada vez mas potencia, también es cierto que la exigencia a estos equipos es mayor y los recursos son limitados. A diferencia de un servidor donde como developers tenemos el poder absoluto del sudo (chiste linuxero). En el browser podríamos tener permisos o no, tener espacio o no. Para resolver estas preguntas tenemos el &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/StorageManager" rel="noopener noreferrer"&gt;StorageManager API&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Esta API nos ofrece métodos como &lt;strong&gt;estimate&lt;/strong&gt; que nos regresa una promesa que objeto con la &lt;em&gt;quota&lt;/em&gt; (espacio máximo que podemos usar), &lt;em&gt;usage&lt;/em&gt; (lo que hemos usado) y usageDetails.&lt;/p&gt;

&lt;p&gt;Cada browser tiene sus políticas para el storage, la quota puede variar incluso la parte de permisos. También hay que mencionar que cada storage tiene también sus limitantes, esto nos deja otro constraint.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;No asumas que toda la data que intentas guardar va a persistir&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Si quieres saber mas del Storage y la persistencia, te recomiendo leer este &lt;a href="https://web.dev/articles/persistent-storage" rel="noopener noreferrer"&gt;artículo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;El storage manager tiene 2 métodos llamados &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/StorageManager/persist" rel="noopener noreferrer"&gt;persist&lt;/a&gt; y &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/StorageManager/persisted" rel="noopener noreferrer"&gt;persisted&lt;/a&gt; que nos ayudan con la cuestion de permisos.&lt;/p&gt;

&lt;p&gt;Nota: Los storage se categorizan en 2 "Best Effort" y "Persistent". Para mas detalles consulta este &lt;a href="https://web.dev/articles/storage-for-the-web#eviction" rel="noopener noreferrer"&gt;artículo&lt;/a&gt;. También te recomendamos esta referencia de &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Storage_API/Storage_quotas_and_eviction_criteria" rel="noopener noreferrer"&gt;como el browser administra las quotas&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusiones
&lt;/h2&gt;

&lt;p&gt;La persistencia involucra factores a tomar en cuenta como Permisos y Quotas. Y estos pueden ser determinados por las políticas de cada navegador y el dispositivo donde se ejecuta nuestra web.&lt;/p&gt;

&lt;p&gt;¿Vale la pena saber esto? Claro, el tener conocimiento de estas APIs, sus beneficios y sus limitantes nos da herramientas para brindar una mejor experiencia a los usuarios y ellos son lo mas importante.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>frontend</category>
      <category>database</category>
    </item>
    <item>
      <title>Sincronizando data entre tabs</title>
      <dc:creator>Joel Humberto Gómez Paredes</dc:creator>
      <pubDate>Mon, 24 Jun 2024 01:10:26 +0000</pubDate>
      <link>https://dev.to/dezkareid/sincronizando-data-entre-tabs-5951</link>
      <guid>https://dev.to/dezkareid/sincronizando-data-entre-tabs-5951</guid>
      <description>&lt;p&gt;Una de las cosas mas complicadas de entender y manejar en una aplicación es el estado de una aplicación. Aunque tenemos herramientas como Redux, Zustand o cualquier otra biblioteca JS que salga en los próximos minutos que te tome leer este post.&lt;/p&gt;

&lt;p&gt;Pero este post no se trata de bibliotecas, se trata de la plataforma y como sincronizamos datos entre las diferentes tabs que pueden estar abiertas en el navegador.&lt;/p&gt;

&lt;p&gt;El navegador administra la memoria de una tab de manera individual pero la capa de datos se administra por dominio. Tenemos varias alternativas para almacenar datos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/es/docs/Web/API/Window/localStorage" rel="noopener noreferrer"&gt;LocalStorage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Cookies&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Cache" rel="noopener noreferrer"&gt;Cache API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API" rel="noopener noreferrer"&gt;IndexedDB&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;File System Access API&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hay muchas formas para almacenar datos y cada una de estas tiene un propósito. Ejemplo, la Cache API esta hecha para almacenar la respuesta de requests de red, lo cual nos sirve features como el modo offline.&lt;/p&gt;

&lt;p&gt;Antes de hablarles de como sincronizar datos entre tabs, me gustaría dejar claro algunos puntos.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;No hay mecanismo que el browser brinde de manera nativa una sincronización entre tabs.&lt;/li&gt;
&lt;li&gt;No toda la información debe sincronizarse.&lt;/li&gt;
&lt;li&gt;Normalmente usamos el servidor como fuente de la verdad y esta bien pero hacer multiples requests para tener la misma información que ya tienes en una tab me parece innecesario.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Para ello exploraremos 2 approaches:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;LocalStorage&lt;/li&gt;
&lt;li&gt;Cualquier Storage que uno quiera + &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API" rel="noopener noreferrer"&gt;Service Workers&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  LocalStorage
&lt;/h2&gt;

&lt;p&gt;Esta opción es la menos recomendada porque es síncrona y ocupa el thread principal de ejecución de JS, pero siendo honestos es uno de los storages mas utilizados.&lt;/p&gt;

&lt;p&gt;El objeto window tiene asociado un evento "storage", el cual se ejecuta cada vez que el storage cambia. Este se ejecutará en cada uno de nuestros tabs entonces con simplemente suscribirnos al evento podemos saber si algo cambió (se ejecuta en todos menos en el tab donde se ejecutó el cambio).&lt;/p&gt;

&lt;p&gt;Vamos a hacer una página simple donde tengamos un contador y un botón para incrementar. El requerimiento es que cada vez que de click el contador se incremente se refleje en todas las tabs que tengamos abiertas.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm0cxy4gtcxufqdqy1vee.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm0cxy4gtcxufqdqy1vee.png" alt="Contador" width="568" height="386"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nota: Sugiero usar un folder y serve como servidor estático&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Sync local storage&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h1&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"counter"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;0&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"increase"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Increase&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
      &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;increase&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;counter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;counter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;counter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;storage&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;counter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;counter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;counter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;load&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;counter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;counter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La parte importante de esta página es suscribirse al evento de cambio del localStorage.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;storage&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;counter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;counter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;counter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;El &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/storage_event" rel="noopener noreferrer"&gt;evento storage&lt;/a&gt; tiene una propiedad llamada key, mediante la cual podemos saber que cambió, este paso es crucial porque el storage es solo uno. Entonces esta al alcance de extensiones o cualquier otro script que se ejecute en el contexto de la aplicación. En este evento podríamos poner dispatchers o lo que queramos que reflejo el cambio que queremos a nuestro state manager.&lt;/p&gt;

&lt;p&gt;La ventaja de este approach es que es fácil, ya tenemos un sistema de eventos incluido que evita la redundancia (evita disparar el evento en la tab donde se ejecutó)&lt;/p&gt;

&lt;p&gt;La desventaja ... es el localStorage, todos tienen acceso y es síncrono, además de que solo puedes guardar strings así que debes hacer parseos para guardar estados complejos y si quieres ejecutar acciones solo para ciertas partes de tu state manager tendrás que verificar que solo se disparen cambios si la data cambió (algunos state managers ya incluyen esta funcionalidad).&lt;/p&gt;

&lt;h2&gt;
  
  
  Cualquier Storage + Service Workers
&lt;/h2&gt;

&lt;p&gt;Este approach es un poco más complicado pero en lo personal lo prefiero, por la simple y sencilla razón de que no es el local storage.&lt;/p&gt;

&lt;p&gt;Para esto necesitamos una pieza de software centralizada que actue como un pubsub para la administración de eventos. En este caso usaremos un service worker ya que es una instancia compartida por todas las tabs (clients).&lt;/p&gt;

&lt;p&gt;Las tareas del service worker serán las siguientes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Suscribirse a un evento que nos diga que se quiere hacer un incremento&lt;/li&gt;
&lt;li&gt;Hacer un update en nuestra base de datos (en este caso usaremos indexeddb)&lt;/li&gt;
&lt;li&gt;Mandar un evento que le indique a todos los tabs(clients) que hubo un incremento.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Este service worker cumple con ese objetivo&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;request_increment&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;incrementValueInDB&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;incrementValueInDB&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;indexedDB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;APPDB&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onupgradeneeded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createObjectStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;count&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;keyPath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onsuccess&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;transaction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;count&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;readwrite&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;objectStore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;objectStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;count&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;objectStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onsuccess&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;requestUpdate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;objectStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;put&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;requestUpdate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onsuccess&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clients&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;matchAll&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;clients&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;clients&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;postMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;has_increment&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;El primer paso consiste en suscribirse a los mensajes y filtrarlos, ya que al ser una instancia compartida muchos mensajes pueden llegar.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;request_increment&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;incrementValueInDB&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La segunda parte es el código donde se actualizará la base de datos. Los service workers tienen acceso a IndexedDB así que ahí hacemos el incremento (aquí depende de la API que quieran usar, por eso no hay código)&lt;/p&gt;

&lt;p&gt;La tercera parte consiste en avisar a los demas que hubo un incremento.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clients&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;matchAll&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;clients&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;clients&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;postMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;has_increment&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Listo, con esto terminamos el service worker y ahora les comparto el código del HTML/JS&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Sync local storage&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h1&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"counter"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;0&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"increase"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Increase&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
      &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;increase&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;serviceWorker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;postMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;request_increment&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;

      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;serviceWorker&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;load&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;indexedDB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;APPDB&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

          &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onupgradeneeded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createObjectStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;count&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;keyPath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
          &lt;span class="p"&gt;};&lt;/span&gt;

          &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onsuccess&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;transaction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;count&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;readwrite&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;objectStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;count&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getRequest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="nx"&gt;getRequest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onsuccess&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
              &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
              &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;counter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;};&lt;/span&gt;
          &lt;span class="p"&gt;};&lt;/span&gt;
          &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;serviceWorker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/sw.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;registration&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;serviceWorker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;has_increment&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;indexedDB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;APPDB&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                  &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onsuccess&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;transaction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;count&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;readwrite&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;objectStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;count&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getRequest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                    &lt;span class="nx"&gt;getRequest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onsuccess&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                      &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;counter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                    &lt;span class="p"&gt;};&lt;/span&gt;
                  &lt;span class="p"&gt;};&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
              &lt;span class="p"&gt;});&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ServiceWorker registration failed: &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt; 
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En la aplicación el código mas importante es la parte de enviar el evento de incrementar&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;increase&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;serviceWorker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;postMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;request_increment&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Y suscribirnos al evento "has_increment" para tomar el dato del local storage&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;serviceWorker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;has_increment&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;indexedDB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;APPDB&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                  &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onsuccess&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;transaction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;count&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;readwrite&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;objectStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;count&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getRequest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                    &lt;span class="nx"&gt;getRequest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onsuccess&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                      &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;counter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                    &lt;span class="p"&gt;};&lt;/span&gt;
                  &lt;span class="p"&gt;};&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
              &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nota: Si quieres hacer alguna modificación se cauteloso porque los service workers son difíciles de depurar&lt;/p&gt;

&lt;p&gt;La ventaja de este enfoque es que no se bloquea el main thread de JS ya que la parte de actualización de datos se hace directamente en el worker y que es hasta cierto punto agnóstica ya que podemos usar cualquier store accesible por un worker.&lt;/p&gt;

&lt;p&gt;La desventaja es que tiende a ser un poco complicado&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusión
&lt;/h2&gt;

&lt;p&gt;Ambos enfoques funcionan, dependerá de la arquitectura de la aplicación el decidir cual usar&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>frontend</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Camino a ser experto en web performance - Performance budgets</title>
      <dc:creator>Joel Humberto Gómez Paredes</dc:creator>
      <pubDate>Mon, 25 Mar 2024 03:36:44 +0000</pubDate>
      <link>https://dev.to/dezkareid/camino-a-ser-experto-en-web-performance-performance-budgets-1ki6</link>
      <guid>https://dev.to/dezkareid/camino-a-ser-experto-en-web-performance-performance-budgets-1ki6</guid>
      <description>&lt;p&gt;En un post anterior hablamos sobre la &lt;a href="https://dev.to/dezkareid/camino-a-ser-experto-en-web-performance-cultura-del-performance-46md"&gt;cultura del performance&lt;/a&gt;, esta es la continuación donde hablaremos de como esa cultura se convierte performance budgtes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh63lwa832wua1lwacc3t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh63lwa832wua1lwacc3t.png" alt="Meme: ahora si se viene lo chido" width="480" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance budgets
&lt;/h2&gt;

&lt;p&gt;Los performance budgets son presupuestos que tenemos para que nuestra web pueda operar. Exacto, PRESUPUESTOS; como en las finanzas personales (al menos las sanas) uno establece presupuestos al hacer compras como televisiones, autos, despensa (comida del mes), salidas por la noche, figuritas y coleccionismo (no tengo finanzas sanas con las figuritas XD).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Budget hace alusión a presupuesto pero en la realidad puede ser manejado como un contrato, límite o incluso como una meta. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Como todo presupuesto, puede crecer o reducir dependiendo de lo que se necesite y no se acumula (eso es ahorro). En el desarrollo web del día a día esto no nos preocupa para nada, lo mas cercano a presupuesto que nos preocupa es la cuenta de nuestro proveedor de la nube.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fozqvlaso25q84nz4tmo5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fozqvlaso25q84nz4tmo5.png" alt="Meme: ya muestranos los performance budgets" width="640" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;¿Cómo defino estos performance budgets? Bueno, a diferencia de nuestras finanzas personales estas son un poco mas complejas (creo). Debido a que los performance budgets involucran una serie de métricas que están relacionadas con todo aquello que afecta nuestra web (y pueden chocar entre si). Estas métricas están agrupadas en 3 grupos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Milestone timings ⏱️&lt;/li&gt;
&lt;li&gt;Quantity-based metrics ⚖️&lt;/li&gt;
&lt;li&gt;Rule-based metrics 💯&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Milestone timings ⏱️
&lt;/h3&gt;

&lt;p&gt;Métricas definidas por eventos en el browser (como &lt;a href="https://developer.mozilla.org/docs/Web/Events/DOMContentLoaded" rel="noopener noreferrer"&gt;DOMContentLoaded&lt;/a&gt;). Todas estás métricas tienen como base intervalos de tiempo&lt;/p&gt;

&lt;p&gt;Estas pueden medirse usando directamente desde la API del browser. Pueden ser una combinación de varios eventos o pueden ser eventos que involucren alguna interacción con el usuario y que tán rápido este obtiene una respuesta a esa interacción.&lt;/p&gt;

&lt;p&gt;Un ejemplo son las &lt;a href="https://web.dev/articles/user-centric-performance-metrics" rel="noopener noreferrer"&gt;metricas centradas en el usuario&lt;/a&gt; o &lt;a href="https://web.dev/articles/vitals#core-web-vitals" rel="noopener noreferrer"&gt;core web vitals&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Es un tema bastante extenso que aborademos en otros posts&lt;/p&gt;

&lt;h3&gt;
  
  
  Quantity-based ⚖️
&lt;/h3&gt;

&lt;p&gt;Métricas definidas por el tamaño o cantidad de los assets/recursos que usas en tu web. Cuando se trata de tamaño normalmente usamos kilobytes o megabytes.&lt;/p&gt;

&lt;p&gt;Todo aquello que afecta a la carga de tu web: Documents, estilos externos, imágenes, scripts y bibliotecas de terceros.&lt;/p&gt;

&lt;p&gt;Es un tema bastante extenso que aborademos en otros posts&lt;/p&gt;

&lt;h3&gt;
  
  
  Rule-based 💯
&lt;/h3&gt;

&lt;p&gt;Métricas definidas por herramientas de auditoria como &lt;a href="https://developer.chrome.com/docs/lighthouse/overview" rel="noopener noreferrer"&gt;lighthouse&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Lighthouse puede auditar varios aspectos de una aplicación como accesibilidad pero nos enfocaremos en performance &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Usando como ejemplo lighthouse, una de sus métricas se llama &lt;a href="https://developer.chrome.com/docs/lighthouse/performance/performance-scoring#metric-scores" rel="noopener noreferrer"&gt;performance score&lt;/a&gt;. Esta se define por un conjunto de buenas prácticas definidas en la industria y su estado actual. Revisa esta tool llamada &lt;a href="https://googlechrome.github.io/lighthouse/scorecalc/" rel="noopener noreferrer"&gt;Lighthouse Scoring Calculator&lt;/a&gt; para que conozcas mas acerca de esto)&lt;/p&gt;

&lt;p&gt;Ya se la saben, tema extenso. Se va para mi backlog de posts&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpk7irgmdt1hfp5qgvcbg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpk7irgmdt1hfp5qgvcbg.png" alt="Meme: Lo repites tanto que ya ha perdodo su significado" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  De un objetivos a performance budgets
&lt;/h3&gt;

&lt;p&gt;En posts anteriores hablamos sobre que debemos estar alineados por ciertos objetivos que todo el equipo entienda. Estos objetivos serán la base de nuestros budgets.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Nuestra página principal debe cargar en 2.5 segundos o menos, en dispositivos móviles de gama media con una conexión 3G normal&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;De este objetivo podemos definir algunos budgets&lt;/p&gt;

&lt;p&gt;En métricas Milestone timings podemos definir el siguiente budget:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;El &lt;a href="https://web.dev/articles/lcp" rel="noopener noreferrer"&gt;Largest ContentFul Paint&lt;/a&gt;(LCP) de la página principal debe ser menor de 2.5 segundos&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://web.dev/articles/fcp" rel="noopener noreferrer"&gt;El First ContentFul Paint&lt;/a&gt;(FCP) de la página debe ser menor a 2s &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;En métricas Quantity-based es un poco mas complejo ya que debemos tomar en cuenta la velocidad de la red ya que eso nos dice cuanta información se puede transmitir. Esa sería nuestra base para el budget&lt;/p&gt;

&lt;p&gt;Tomando en cuenta que una conexión 3g normal, le descarga es de descarga 780kilobits por segundo, en 2.5 segundo podemos descargar tenemos 1950 kilobits, esto expresado en kilobytes serían un poco mas de 240kb (243.75)&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Por ende la suma de todos tus assets no debe pasar de este peso o ninguno de tus assets debería pesar mas de lo que puedes transferir (puede haber excepciones)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Y a partir de eso podemos definir los budgets para cada uno de los assets que ocupamos en nuestra página. En este caso vamos a usar &lt;a href="https://www.performancebudget.io/" rel="noopener noreferrer"&gt;performancebudget.io&lt;/a&gt; para empezar a hacer ese budget.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Selecciona en tipo de metricas assets&lt;/li&gt;
&lt;li&gt;Selecciona la velocidad de conexión (3G Slow de 780kb)&lt;/li&gt;
&lt;li&gt;Escribe la velocidad en segundos(2.5)&lt;/li&gt;
&lt;li&gt;Modifica los valores que se adapten a lo que necesites&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;En esta parte del proceso tendremos algo similar a esto&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F704r5ajnh3g2oir2dz4v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F704r5ajnh3g2oir2dz4v.png" alt="Selección del tamaño de los assets" width="800" height="573"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;En el siguiente paso se nos muestra un resumen de nuestro budget&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc0ct5fm28w3gczce57xt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc0ct5fm28w3gczce57xt.png" alt="Performance budget" width="800" height="412"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ademas del tiempo de descarga estimada para otras velocidades de red&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx63rtu615ms4js862ush.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx63rtu615ms4js862ush.png" alt="Tabla de velocidades del performance budget" width="800" height="879"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Finalmente puedes descargarlo en un formato que es compatible con lighthouse-ci (explicaré esto en un post dedicado a auditorias)
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"resourceSizes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"resourceType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"document"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"budget"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"resourceType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"stylesheet"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"budget"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;7.8&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"resourceType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"script"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"budget"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;39.6&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"resourceType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"image"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"budget"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;151.2&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"resourceType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"media"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"budget"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;23.4&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"resourceType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"font"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"budget"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"timings"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En un lenguaje mas humano podemos decir que:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;La página principal debe cargar 6kb de html o menos&lt;/li&gt;
&lt;li&gt;La página principal debe cargar 7.8kb de css o menos&lt;/li&gt;
&lt;li&gt;La página principal debe cargar 39.6kb de JS o menos&lt;/li&gt;
&lt;li&gt;La página principal debe cargar 151.2kb de imagenes o menos&lt;/li&gt;
&lt;li&gt;La página principal debe cargar 23.4kb de recursos multimedia o menos&lt;/li&gt;
&lt;li&gt;La página principal debe cargar 12kb de fuentes o menos&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Listo ya tenemos nuestros budgets en terminos de Quantity-based&lt;/p&gt;

&lt;p&gt;En métricas Rule-based podemos ir a &lt;a href="https://googlechrome.github.io/lighthouse/scorecalc/" rel="noopener noreferrer"&gt;lighthouse scoring calculator&lt;/a&gt; y definir nuestro budget, seleccionando la versión de Lighthouse (10) y el tipo de target (mobile). En este caso nuestro budget es una combinación de métricas (algunas que definimos ya en milestone timings)&lt;/p&gt;

&lt;p&gt;Al agregar el límite máximo de nuestros budgets a lighthouse podemos ver el score aproximado que deberiamos de tener, en este caso: 93.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft6aatsz8x81pycnuo68e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft6aatsz8x81pycnuo68e.png" alt="Lighthouse score calculator" width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Y finalmente con todo esto podemos tener nuestro budget:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;El score en performance de la página principal debe ser al menos de 93% en lighthouse&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Este es un ejemplo de budget que podría ser visto como una meta que fija un límite para ir hacia adelante.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dificultad al definir budgets
&lt;/h2&gt;

&lt;p&gt;Una de las partes complejas de crear budgets es entender que estos pueden estar relacionados y el modificar uno puede presentar un side-effect en otro.&lt;/p&gt;

&lt;p&gt;Ejemplo el FCP y el LCP, si tu HTML y CSS que necesitas para renderizar tu aplicación sobrepasan 240kb y tu budget es para conexión 3G vas a tener problemas.&lt;/p&gt;

&lt;p&gt;Si tus métricas tienen que ver con &lt;a href="https://web.dev/articles/tti" rel="noopener noreferrer"&gt;TTI&lt;/a&gt;, &lt;a href="https://web.dev/articles/inp" rel="noopener noreferrer"&gt;INP&lt;/a&gt; o &lt;a href="https://web.dev/articles/fid" rel="noopener noreferrer"&gt;FID&lt;/a&gt; pero tienes un uso excesivo de JS, tendrás problemas.&lt;/p&gt;

&lt;p&gt;Es por ello que los performance budgets deben partir de objetivos alineados a tu negocio donde el foco este en la experiencia de los usuarios que te generen mejor revenue, tomando en cuenta las condiciones de estos como base.&lt;/p&gt;

&lt;p&gt;Puedes optimizar para conexiones 3G y los usuarios con 4G tendrán un sitio más rápido. Si la experiencia es buena en conexiones lentas, podría ser mejor para conexiones rápidas o no? No necesariamente&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh9nugxf3qhhuq9rt6h38.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh9nugxf3qhhuq9rt6h38.png" alt="Meme: Por un demonio lo que faltaba" width="600" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Si bien la rápidez es parte clave del performance, no solo se necesita ser rápido sino también usable. Podríamos hacer que un sitio web cumpla con todas las métricas que estableciamos agregando delay de recursos, reduces el tiempo de carga pero podrías aumentar el tiempo en que al usuario le toma hacer lo que necesita.&lt;/p&gt;

&lt;p&gt;Es importante recordar que no todas las métricas de una web deben tener un budget solo las significativas para tu negocio.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;También hay algunos performance budgets que se establecen en base a lo que tu competencia tiene (ya se la saben XD)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Siguientes pasos
&lt;/h2&gt;

&lt;p&gt;Una vez que ya definimos nuestros budgets (no necesariamente se hace en este orden). Lo que sigue es usarlos para auditar nuestras aplicaciones. Eso queda fuera del scope de este post pero voy a dar un adelanto.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdm344hojup68c59y1wpk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdm344hojup68c59y1wpk.png" alt="Meme: It's something (ya es algo)" width="500" height="348"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Así como la pirámide del tests hay auditorias de performance que se realizarán dependiendo del ambiente(stage) de la aplicación. Para obtener feedback lo más rápido posible sin tener que llegar al stage de producción.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Un budget es una descripción que nos guía a una implementación&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Hay algunos bundlers como webpack que tiene ciertas &lt;a href="https://webpack.js.org/configuration/performance/" rel="noopener noreferrer"&gt;configuraciones de performance&lt;/a&gt; pueden servirnos en ambiente local para cuidar el tamaño de cierto tipo de assets.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/siddharthkp/bundlesize" rel="noopener noreferrer"&gt;Bundlesize&lt;/a&gt; es una tool que nos puede ayudar en CI como gatekeeper para cuidar que nuestros performance budgets de tipo Quantity se cumplan.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/GoogleChrome/lighthouse-ci" rel="noopener noreferrer"&gt;Lighthouse-ci&lt;/a&gt; nos puede ayudar para realizar auditorias de performance budget de tipo rule-based pero también de milestone timings y quantity. En un ambiente CI pero también en ambientes de Quality Assurance.&lt;/p&gt;

&lt;p&gt;Y un overview de herramientas más robustas como &lt;a href="https://www.webpagetest.org/" rel="noopener noreferrer"&gt;webpagetest&lt;/a&gt;, &lt;a href="https://calibreapp.com/" rel="noopener noreferrer"&gt;calibre&lt;/a&gt;, &lt;a href="https://www.speedcurve.com/" rel="noopener noreferrer"&gt;speedcurve&lt;/a&gt;, entre otras. Espero les haya gustado, de ser así compartan, comenten y reaccionen, no va a pasar nada si no lo hacen pero sería genial :D&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>webperf</category>
      <category>performance</category>
    </item>
    <item>
      <title>Camino a ser experto en web performance - Cultura del Performance</title>
      <dc:creator>Joel Humberto Gómez Paredes</dc:creator>
      <pubDate>Tue, 19 Mar 2024 06:12:30 +0000</pubDate>
      <link>https://dev.to/dezkareid/camino-a-ser-experto-en-web-performance-cultura-del-performance-46md</link>
      <guid>https://dev.to/dezkareid/camino-a-ser-experto-en-web-performance-cultura-del-performance-46md</guid>
      <description>&lt;p&gt;Bueno el día de hoy marca un hito en mi carrera profesional como frontend ya que he decidido dar un paso adelante y especializarme en web performance.&lt;/p&gt;

&lt;p&gt;Como parte de eso voy a estar compartiendo una serie de posts que ignoro cuantos sean, solo se que será al menos 1 a la semana con mis aprendizajes en este camino ninja.&lt;/p&gt;

&lt;p&gt;Como frontends tenemos que saber muchas cosas acerca de performance:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Loading performance

&lt;ul&gt;
&lt;li&gt;Diferencias entre protocolos HTTP1 y HTTP2&lt;/li&gt;
&lt;li&gt;Prioridad de descarga de los recurso&lt;/li&gt;
&lt;li&gt;Prefetch, Preload y Preconnect&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Rendering performance

&lt;ul&gt;
&lt;li&gt;Recursos render blocking&lt;/li&gt;
&lt;li&gt;Recursos parsing blocking&lt;/li&gt;
&lt;li&gt;Critical rendering path&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;El costo de JS y el procesamiento de ciertos assets&lt;/li&gt;

&lt;li&gt;Core Web Vitals&lt;/li&gt;

&lt;li&gt;Real User Monitoring&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flvnzojl0sycej7wvqwgh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flvnzojl0sycej7wvqwgh.png" alt="Meme " width="520" height="444"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Probablemente manejes muchos de estos temas y aunque sepas esto, si el performance no es un punto clave del producto en tu organización, no podrás aplicar ese conocimiento para generar un impacto significativo. Para que esto pase debe existir la cultura del performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cultura del performance
&lt;/h2&gt;

&lt;p&gt;Una de las cosa mas geniales de trabajar en un producto es el enfoque, todos miran en la misma dirección y es mucho más fácil cumplir metas cuando toda la organización esta alineada.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx6369oils32rki4jbxhj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx6369oils32rki4jbxhj.png" alt="Meme " width="400" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;El tema de performance normalmente es visto como una actividad asociada al equipo de ingeniería/desarrollo. Si bien la implementación de estrategias recae en ese equipo, se debería involucrar a todos los actores que marcan el rumbo del producto como: Enginer Managers, Designers, Project Managers, etc. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Tomar al performance como una pieza clave para cumplir la metas del negocio. Esta es la cultura del performance.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;En un equipo la cultura es importante ya que nuestras acciones son guiadas por la antes esta. Como en los sistemas de diseño, la mayor parte no recae en la implementación, sino en la comunicación, adopción y contribución.&lt;/p&gt;

&lt;p&gt;¿Cómo comunico que esto es importante?&lt;br&gt;
¿Cómo alinear al equipo?&lt;br&gt;
¿Cómo los miembros del equipo pueden contribuir?&lt;/p&gt;

&lt;p&gt;Responder estas preguntas parece simple pero en la práctica te encontrarás con problemas de varias indoles como:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Excepticismo (no creemos que eso ayude)&lt;/li&gt;
&lt;li&gt;Silos (equipos aislados y no colaboran)&lt;/li&gt;
&lt;li&gt;Falta de apoyo o de "ownership" de tareas asociadas al performance (hay cosas más importantes)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Generar una cultura es complicado, costoso (es una inversión) y mas que nada una tarea de nunca acabar porque aunque tengas ciertas métricas para medir performance, estas pueden ir cambiando de acuerdo a las necesidades del negocio (imagina que tu app es desktop pero te piden dar soporte a resoluciones mobile).&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Cómo comunico que esto es importante?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp73v59eb8i3papxe9kl2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp73v59eb8i3papxe9kl2.png" alt="Meme " width="387" height="423"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DINERO&lt;/strong&gt;, si, &lt;strong&gt;DINERO&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;El performance esta relacionado con la UX, la UX tiene relación con: convertion, retention, revenue, etc. Esto lo pueden entender personas de marketing, management y development.&lt;/p&gt;

&lt;p&gt;Una comunicación es más efectiva cuando se lleva a cabo en términos que todos entendamos. Creo que todos entendemos que sin dinero una empresa no puede operar y entre más genere puede invertir más en su visión y su misión.&lt;/p&gt;

&lt;p&gt;También podemos dar justificaciones mas técnicas de acuerdo a ciertos tipos de perfiles o departamentos. Esto al alcance de una busqueda en Google o en &lt;a href="https://wpostats.com/" rel="noopener noreferrer"&gt;WPO Stats&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Ejemplo:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Nuestro sitio web gastoinnecesario.com tarda 5 segundos en cargar&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Esto no me dice mucho, pero si presentas un caso de estudio como &lt;a href="https://wpostats.com/2015/11/13/auto-anything" rel="noopener noreferrer"&gt;AutoAnything reduced page load time by 50% and saw an 12-13% increase in sales&lt;/a&gt; o un &lt;a href="https://blog.google/products/admanager/showing-why-mobile-speedmatters/" rel="noopener noreferrer"&gt;artículo&lt;/a&gt; de la importancia de la velocidad.&lt;/p&gt;

&lt;p&gt;Es más fácil de comunicar los beneficios de incluir el performance como parte del producto.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Cómo alinear al equipo?
&lt;/h2&gt;

&lt;p&gt;Una vez que entendemos los beneficios nos toca pensar como estamos alineados.&lt;/p&gt;

&lt;p&gt;Eso lo logramos a traves de los &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Performance/Performance_budgets" rel="noopener noreferrer"&gt;performance budgets&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnwmrcx1n5k2gg0wmlzx0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnwmrcx1n5k2gg0wmlzx0.png" alt="Meme " width="400" height="296"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Los performance budgets son acuerdos, es un presupuesto que los involucrados en el producto deben respetar. Es algo que hace más fácil entender y tomar en cuenta el impacto de las decisiones que se toman ya que hay un límite definido.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Deciding a page can’t exceed 500kB when a mock-up containing three carousels and a full-screen high-resolution background image has already been approved isn’t going to do you much good" - Tim Kadlec&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;No todos los performance budgets son exclusivos de ingeniería, a nivel implementación nosotros podemos representarlos en cierto formato pero al final los budgets son presupuestos entendibles para todos expresados en texto comprensible. Ejemplo:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Nuestra página principal debe cargar en 2.5 segundos o menos, en dispositivos móviles de gama media con una conexión 3G normal&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Esto hace que cada perfil piense que puede hacer para respetar ese presupuesto.&lt;/p&gt;

&lt;p&gt;Este budget me dice que bajo ciertas condiciones el tamaño de los assets que ocupa la página no puede ser mayor de lo que se puede transmitir en ese periodo de tiempo.&lt;/p&gt;

&lt;p&gt;No voy a ahondar mucho en esto, porque ya tengo en mente otro posts donde abordaré esto de manera mas profunda (probablemente sea otra serie). Pero si quieres entrarle al chisme te recomiendo este &lt;a href="https://addyosmani.com/blog/performance-budgets/" rel="noopener noreferrer"&gt;artículo&lt;/a&gt; de &lt;a href="https://twitter.com/addyosmani" rel="noopener noreferrer"&gt;Addy Osmani&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Cómo los miembros del equipo pueden contribuir?
&lt;/h2&gt;

&lt;p&gt;Honestamente no importa que tanto tiempo dediques a esto no es suficiente, debes tener: advocates, embajadores, champions, colaboradores, etc.&lt;/p&gt;

&lt;p&gt;Por eso es importante que el primer punto quede muy claro, eso hará que todos nos alineemos y se designe tiempo para dedicarlo a performance.&lt;/p&gt;

&lt;p&gt;También hay que generar documentación sobre donde encontrar los performance budgets, las herramientas que se van a utilizar, en que partes del proceso se harán auditorias de estos budgets y en que casos se pueden hacer excepciones.&lt;/p&gt;

&lt;p&gt;Como toda iniciativa hay que reducir la fricción, honestamente creo que nadie estaría de acuerdo con tener una aplicación con bajo performance, pero a veces hay ciertas features que pueden ser críticas y probablemente sean más importantes que tener un desempeño optimo. Si dejamos claro cuando podemos modificar el budget o hacer excepciones es más simple que las personas se sumen.&lt;/p&gt;

&lt;p&gt;En otros posts veremos como definir performance budgets y los tipos de métricas, espero les haya gustado y puedan compartir.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>performance</category>
    </item>
    <item>
      <title>CSS @layer: ¿Héroe o amenaza?</title>
      <dc:creator>Joel Humberto Gómez Paredes</dc:creator>
      <pubDate>Mon, 18 Mar 2024 05:04:11 +0000</pubDate>
      <link>https://dev.to/dezkareid/css-layer-heroe-o-amenaza-gdf</link>
      <guid>https://dev.to/dezkareid/css-layer-heroe-o-amenaza-gdf</guid>
      <description>&lt;p&gt;La vida del developer es una vida donde siempre vas a estar aprendiendo. Ya sea por los cambios constantes del mercado, la organización, nuevas tools que te ayudan a hacer mejor tu trabajo, nuevas features que se remueven/agregan a la plataforma o alguna IA que te va a robar el trabajo (saludos al Devin XD)&lt;/p&gt;

&lt;p&gt;Hoy vamos a hablar de &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/@layer" rel="noopener noreferrer"&gt;@layer&lt;/a&gt;, una regla de CSS que viene a resolver uno de los tantos "problemas" que podemos tener en la creación de estilos ... "LA ESPECIFICIDAD".&lt;/p&gt;

&lt;p&gt;En si no hay ningún problema pero cuando manejamos aplicaciones grandes es complicado manejar la especificidad. Si bien podemos usar metodologías para organizar nuestro CSS y controlar el origen y la especificidad; hay una pieza faltante que esta regla puede resolver ... definir la prioridad (sin usar &lt;code&gt;!important&lt;/code&gt;) de manera consistente.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgwa8r6n3o1ontlhyccaf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgwa8r6n3o1ontlhyccaf.png" alt="Meme: ah caray eso si me interesa" width="400" height="297"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  CSS at-rule @layer
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;@layer&lt;/code&gt; esta en &lt;a href="https://developer.mozilla.org/en-US/blog/baseline-unified-view-stable-web-features/" rel="noopener noreferrer"&gt;baseline&lt;/a&gt; desde 2022, aunque en algunos Browsers de Android se agregó hasta marzo de 2024 (según &lt;a href="https://caniuse.com/mdn-css_at-rules_layer" rel="noopener noreferrer"&gt;caniuse&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Antes de continuar, quiero que hagamos 2 cosas simples:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Cada vez que te veas el texto "Atinale al color", lee el código y responde cual color será el del elemento.&lt;/li&gt;
&lt;li&gt;Realiza el ejercicio y verifica la respuesta.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Para mi es como un juego, te podría sorprender y ciertamente hará esto menos aburrido.&lt;/p&gt;

&lt;p&gt;Ahora si, haremos varios mini demos simples pero inquebrantables.&lt;/p&gt;

&lt;p&gt;Primero crea un &lt;code&gt;index.html&lt;/code&gt; con el siguiente contenido&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"layer.css"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;main&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"main"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Y ahora vamos crear un archivo &lt;code&gt;layer.css&lt;/code&gt; y agregar el siguiente código&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.main&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.main&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Atinale al color&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SPOILER ALERT&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;..........&lt;/p&gt;

&lt;p&gt;Creo que estuvo fácil o quizás no, es azul.&lt;/p&gt;

&lt;p&gt;Y si cambias por este código?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;theme&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.main&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.main&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Atinale al color&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SPOILER ALERT&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;..........&lt;/p&gt;

&lt;p&gt;Esto es juego de niños, es azul.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftqgrte3s0ruuvxvladrr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftqgrte3s0ruuvxvladrr.png" alt="Meme: Y eso que decian que nunca iba a servir para nada" width="735" height="552"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ahora, un poco de explicación teoría aburrida. &lt;code&gt;@layer&lt;/code&gt; es una &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/At-rule" rel="noopener noreferrer"&gt;CSS at-rule&lt;/a&gt;, quiere decir que esta internamente tiene un bloque de código y esta puede tener un nombre o no tenerlo. &lt;/p&gt;

&lt;p&gt;Y si cambias por este código?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;theme&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.main&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;dummy&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.main&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;red&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.main&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Atinale al color&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SPOILER ALERT&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;..........&lt;/p&gt;

&lt;p&gt;Too easy, es rojo, seguramente te estas replanteando que haces aún aquí leyendo esto, vamos hacerlo más interesante. Cuando usas &lt;code&gt;@layer&lt;/code&gt;, las declaraciones posteriores siempre tendrán mas prioridad que las primeras.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;theme&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="nc"&gt;.main&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;dummy&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.main&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;red&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.main&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Atinale al color&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fog4ujfheo6ndu04rb9s5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fog4ujfheo6ndu04rb9s5.png" alt="Meme: asustado potter? " width="480" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SPOILER ALERT&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;..........&lt;/p&gt;

&lt;p&gt;Probablemente si nos basamos en la espeficidad tu respuesta fue azul, pero la regla &lt;code&gt;@layer&lt;/code&gt; lo que predomina es el orden no la especificidad, incluso si agregaras un id en el selector del layer &lt;strong&gt;theme&lt;/strong&gt; funcionaría igual (hazlo para que veas que no te miento).&lt;/p&gt;

&lt;p&gt;Here we go again&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;theme&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.main&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;blue&lt;/span&gt; &lt;span class="cp"&gt;!important&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;dummy&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.main&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;red&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.main&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Atinale al color&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SPOILER ALERT&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;..........&lt;/p&gt;

&lt;p&gt;Recuerden, la cascada es la que determina que estilos se aplican. En esta se toma en cuenta la ubicación y la importancia. En este caso la &lt;code&gt;@layer theme&lt;/code&gt; aplica un estilo con &lt;code&gt;!important&lt;/code&gt;, eso hace que el orden e incluso la especificidad no importen.&lt;/p&gt;

&lt;p&gt;Esto se puso mas interesante&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;theme&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.main&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;blue&lt;/span&gt; &lt;span class="cp"&gt;!important&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;dummy&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.main&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;red&lt;/span&gt; &lt;span class="cp"&gt;!important&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.main&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Atinale al color&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqwn8hizpj54gaozl1ajo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqwn8hizpj54gaozl1ajo.png" alt="Meme: por fin un digno oponente" width="344" height="313"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SPOILER ALERT&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;..........&lt;/p&gt;

&lt;p&gt;Seguro pensaste que era rojo, yo también lo pensé pero al parecer una layer que aplique un estilo con &lt;code&gt;!important&lt;/code&gt; prevalecerá sobre otro que venga después, sin importar la especificidad. Es por eso que &lt;code&gt;@layer&lt;/code&gt; puede ser héroe o villano. Aunque si usas layers, el uso de &lt;code&gt;!important&lt;/code&gt; debería estar prohibido.&lt;/p&gt;

&lt;p&gt;Esto se puso interesante&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;dummy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;theme&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.main&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;dummy&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.main&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;red&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.main&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Atinale al color&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SPOILER ALERT&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnspxmhbcmtnws1o32kna.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnspxmhbcmtnws1o32kna.png" alt="Meme: tranquilo tampoco lo entendí a la primera" width="640" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;..........&lt;/p&gt;

&lt;p&gt;@layer se puede declarar e inmediatamente colocar un bloque o puede declararse y posteriormente definir el bloque. El orden en que se definan le dara la prioridad. Recuerda las primeras siempre tendrán menos priordad que las últimas. Por ende el color es azul, aunque solo se hubiera puesto &lt;code&gt;@layer dummy&lt;/code&gt;; hubiera dado el mismo resultado&lt;/p&gt;

&lt;p&gt;Vamos con otro, ya casi llegamos al final&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;theme&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.main&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;dummy&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="nc"&gt;.main&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;red&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.main&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;green&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Atinale al color&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SPOILER ALERT&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;..........&lt;/p&gt;

&lt;p&gt;Y el color es ...&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb6x93cmmp3wlkte2u3os.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb6x93cmmp3wlkte2u3os.png" alt="Meme: verde, verde como que?" width="780" height="591"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Verde. Los estilos fuera de las capas tie&lt;a href="https://dev.tourl"&gt;&lt;/a&gt;nen mayor prioridad que las que tienen capas, incluso aunque pusieras la declaración de estilos antes de la declaración de @layer tendría exactamente los mismos efectos, a menos que usaras !important. Lo cual agrega mayor prioridad, vamos intentalo.&lt;/p&gt;

&lt;p&gt;Ok, ya estamos cerca del final, este es el último mini demo, respira hondo, vacia tu mente, deja que tu mente fluya por la cascada, se la cascada&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;dummy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;theme&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.main&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;blue&lt;/span&gt; &lt;span class="cp"&gt;!important&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;dummy&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="nc"&gt;.main&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;red&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="nc"&gt;.main&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;green&lt;/span&gt; &lt;span class="cp"&gt;!important&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Atinale al color&lt;/p&gt;

&lt;p&gt;SPOILER ALERT&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgrl0r0n2xsnkajt1do0l.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgrl0r0n2xsnkajt1do0l.jpeg" alt="Meme: era yo azul" width="477" height="272"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;..........&lt;/p&gt;

&lt;p&gt;Casi podría apostar que pensaste que era verde, es mas si lo pensaste mandame un &lt;a href="https://twitter.com/DezkaReid" rel="noopener noreferrer"&gt;tweet&lt;/a&gt;, mencioname en un &lt;a href="https://www.linkedin.com/in/joelhumberto/" rel="noopener noreferrer"&gt;post&lt;/a&gt; o lo que mas te agrade y pon "Yo también pensé que era verde". Pero es azul, recuerda &lt;code&gt;!important&lt;/code&gt; define prioridad, pero cuando 2 estilos son importantes el origen de donde se declara tiene más relevancia.&lt;/p&gt;

&lt;p&gt;Cada &lt;code&gt;@layer&lt;/code&gt; puede tener incluso nested layer pero no abordaremos ese tema en este momento, porque ya me extendí y hay algo muy importante que debo decirte antes.&lt;/p&gt;

&lt;p&gt;Bueno ahora la parte mas importante de este post, no es seguro usar este feature de momento si mantienes una misma base de código o estilos para mobile :(&lt;/p&gt;

&lt;p&gt;Si bien esta disponible desde 2022, si una buena parte de tu mercado es Android probablemente no sea buena idea usarla, revisa caniuse y el tipo de usuarios que llegan a tus aplicaciones para saber si es seguro usarla.&lt;/p&gt;

&lt;p&gt;En este caso &lt;code&gt;@supports&lt;/code&gt; no nos va a servir, porque esta solo evualua si un estilo es válido no tiene soporte para &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/At-rule" rel="noopener noreferrer"&gt;at-rules&lt;/a&gt;. Este soporte esta en &lt;a href="https://github.com/w3c/csswg-drafts/issues/6966" rel="noopener noreferrer"&gt;discusión&lt;/a&gt;, así que mientras tanto el uso de &lt;code&gt;@supports at-rule(@layer)&lt;/code&gt; tiene un futuro incierto.&lt;/p&gt;

&lt;p&gt;Podríamos usar Javascript para saber si tiene soporte&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;CSSLayerBlockRule&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;undefined&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Si tenemos soporte :D&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pero esto solo agregaría un blocker mas al parsing y al rendering, ademas de tener que generar estilos que soporten &lt;code&gt;@layer&lt;/code&gt; y un fallback que no, mucha arquitectura que podría no valer la pena. Pero como dije, todo dependerá de nuestros usuarios.&lt;/p&gt;

&lt;p&gt;Gracias por llegar hasta aquí, te dejo un &lt;a href="https://codepen.io/dezkareid/pen/oNOYQeP" rel="noopener noreferrer"&gt;pen&lt;/a&gt; con un código similar al del último mini demo, si puedes comparte y espero que hayas aprendido algo (aunque no vayas a usar esta feature)&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>css</category>
    </item>
    <item>
      <title>@supporting lo insoportable en tu CSS</title>
      <dc:creator>Joel Humberto Gómez Paredes</dc:creator>
      <pubDate>Sat, 16 Mar 2024 09:13:14 +0000</pubDate>
      <link>https://dev.to/dezkareid/supporting-lo-insoportable-en-tu-css-4kl4</link>
      <guid>https://dev.to/dezkareid/supporting-lo-insoportable-en-tu-css-4kl4</guid>
      <description>&lt;p&gt;Con el paso del tiempo los major browsers han estado agregando soporte a varias features de CSS, lo cual es bastante genial :D ... pero, siempre hay un pero. Es complicado que todos se pongan de acuerdo y liberen las mismas features importantes a la vez, además de que es prácticamente imposible que todos nuestros usuarios tengan su browser actualizado en todo momento.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyxj6gjoyglbsjxx8r5ih.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyxj6gjoyglbsjxx8r5ih.png" alt="Gatito triste" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;En CSS es complicado seguir una estrategía &lt;a href="https://medium.com/centraalacademy/multi-target-bundling-porque-tenemos-que-pensar-en-el-presente-74d2bf852d72" rel="noopener noreferrer"&gt;multi-target bundle&lt;/a&gt; (En resumen definir un baseline para con un bundle legacy y uno "moderno"). Ya que no tenemos en el tag &lt;a href="https://developer.mozilla.org/es/docs/Web/HTML/Element/link" rel="noopener noreferrer"&gt;link&lt;/a&gt; un atributo similar a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#nomodule" rel="noopener noreferrer"&gt;nomodule del tag script&lt;/a&gt;. Adémas de que este approach poco a poco dejará de ser usado porque cada vez son menos los browsers donde valga la pena dar ese soporte.&lt;/p&gt;

&lt;p&gt;Actualmente lo que hacemos es usar una estrategia de fallbacks para resolver este problema (parcialmente). Definimos un baseline y usando &lt;a href="https://browsersl.ist/" rel="noopener noreferrer"&gt;browserslist&lt;/a&gt; e incluimos &lt;a href="https://postcss.org/docs/postcss-plugins" rel="noopener noreferrer"&gt;plugins de PostCSS&lt;/a&gt; u otras tools que agregarán los fallbacks o mantendrán intactor el código dependiendo de si la feature que usamos tiene soporte o no en el baseline definido.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F04oqitwr4q8464o5zeg4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F04oqitwr4q8464o5zeg4.png" alt="Patricio estrella diciendo " width="339" height="330"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Aún así es complicado soportar ciertas features de CSS modernas o no estandarizadas porque solo sabemos si el soporte existe en tiempo de ejecución y la estrategia mencionada anteriormente se realiza en tiempo de compilación.&lt;/p&gt;

&lt;p&gt;Antes usabamos &lt;a href="https://modernizr.com/" rel="noopener noreferrer"&gt;Modrnizr&lt;/a&gt; pero JS es parse blocking y tendríamos el mismo problema para features nuevas.&lt;/p&gt;

&lt;p&gt;Para esto podemos usar algo que en CSS se llama &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_conditional_rules/Using_feature_queries" rel="noopener noreferrer"&gt;Feature queries&lt;/a&gt;, que al igual que los media queries, son una forma de definir un &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/At-rule#conditional_group_rules" rel="noopener noreferrer"&gt;grupo de reglas basado en ciertas condiciones&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Para esto usamos la regla &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/@supports" rel="noopener noreferrer"&gt;@supports&lt;/a&gt;, esta lo que evalua es que la condición sea válida y solo eso (&lt;a href="https://caniuse.com/css-featurequeries" rel="noopener noreferrer"&gt;caniuse&lt;/a&gt; nos respalda XD).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@supports&lt;/span&gt; &lt;span class="err"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;condicion&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* Tu CSS va aquí */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esto no es nada nuevo, igual y este post no te aporta nada pero vamos a tratar de que lo haga. Con un caso práctico que me sucedio recientemente: &lt;a href="https://web.dev/blog/viewport-units" rel="noopener noreferrer"&gt;Las nuevas unidades del viewport&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Soy fan del &lt;code&gt;min-height: 100vh&lt;/code&gt; pero esta regla no da los resultados deseados en dispositivos móviles debido al comportamiento de la UI, por ejemplo la toolbar que se agrega en la parte de abajo en dispositivos iOS en Safari.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqww3ue0ti8zkwzzlnxn7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqww3ue0ti8zkwzzlnxn7.png" alt="Patricio levantando el meñique" width="736" height="552"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Según &lt;a href="https://caniuse.com/viewport-unit-variants" rel="noopener noreferrer"&gt;caniuse&lt;/a&gt; esta feature esta desde noviembre del 2022 en major browser pero en Android Browser(chromium) se libreró febrero de 2024.&lt;/p&gt;

&lt;p&gt;Ahora vamos a lo bueno, un mini demo. Haremos algo simple, que una página tenga el 100% del viewport, algo común pero muy significativo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3uqdv83r48mu0gyeccmx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3uqdv83r48mu0gyeccmx.png" alt="Meme ahora si se viene lo chido" width="480" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Comenzamos creando un &lt;code&gt;index.html&lt;/code&gt; con el esqueleto de la página&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"styles.css"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Viewport&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;main&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"main"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Creamos nuestro archivo &lt;code&gt;styles.css&lt;/code&gt;. Como primer paso usaremos vh y después agregaremos el soporte.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;html&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.main&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#ffdd00&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c"&gt;/* Si, es el color del super saiyajin */&lt;/span&gt;
  &lt;span class="nl"&gt;min-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100vh&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Si pruebas esto en un iphone, lo mas probable es que tengas un horrible scroll.&lt;/p&gt;

&lt;p&gt;Ahora vamos a agregar el soporte para usar un &lt;code&gt;min-height: 100dvh&lt;/code&gt; pero usando &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties" rel="noopener noreferrer"&gt;custom properties&lt;/a&gt; para no tener que recordar el selector y compartir esto usando la cascada.&lt;/p&gt;

&lt;p&gt;Luciría así&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;html&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;:root&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;--page-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100vh&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@supports&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="n"&gt;dvh&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;:root&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="py"&gt;--page-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="n"&gt;dvh&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.main&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#ffdd00&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;min-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--page-height&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ahora si pruebas en un dispositivo iOS o similar, ese scroll debería haber desaparecido.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9a0y4qv2f0ottp7bwhal.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9a0y4qv2f0ottp7bwhal.png" alt="Meme me atrapaste es cine" width="640" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bueno, vamos a explicar paso por paso. Siguiendo una estrategia estilo progressive enhancement, lo primero que se hace es definir una custom property --page-height en el selector &lt;a href="https://developer.mozilla.org/es/docs/Web/CSS/:root" rel="noopener noreferrer"&gt;:root&lt;/a&gt; con el valor base que debería tomar para representar el alto mínimo de una página.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nd"&gt;:root&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;--page-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100vh&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ahora usaremos supports para asignar el valor a &lt;code&gt;100dvh&lt;/code&gt; a nuestra custom property &lt;code&gt;--page-height&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;La sintaxis me pide evaluar una condición y esta debe ir entre paréntesis, esta condición es formada por &lt;code&gt;&amp;lt;propiedad&amp;gt;: &amp;lt;valor&amp;gt;&lt;/code&gt; (un estilo). Si el estilo es válido la evaluación es verdadera y si no es falsa.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@supports&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="n"&gt;dvh&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;:root&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="py"&gt;--page-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="n"&gt;dvh&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Si dvh no existe como unidad, este bloque jamas se ejecutará porque no sería un estilo válido.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9mv5wb889ldj4e553xdl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9mv5wb889ldj4e553xdl.png" alt="Meme sabes yo también tengo algo de científico" width="720" height="540"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Y al final simplemente usamos la custom property que definimos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.main&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#ffdd00&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;min-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--page-height&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Recomiendo que sigas el ejemplo que hicimos pero si quieres también te dejo un &lt;a href="https://codepen.io/dezkareid/pen/PoLMMVE" rel="noopener noreferrer"&gt;código&lt;/a&gt; similar en codepen. Aunque te recomiendo descargarlo y ejecutarlo en tu maquina porque en los codepen se ejecuta en un iframe (probablemente debí guardarlo en otro lado pero ya estaba ahí XD)&lt;/p&gt;

&lt;p&gt;Gracias por llegar hasta aquí si puedes da like y comparte :)&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
