<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="/feed.xsl"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>TIL de Angel Cruz</title>
    <link>https://www.angelcruz.dev/lab</link>
    <description>Aprendizajes breves, gotchas y notas del día a día en desarrollo web. Una entrada por cosa aprendida.</description>
    <language>es</language>
    <lastBuildDate>Sun, 16 Aug 2026 08:35:46 GMT</lastBuildDate>
    <atom:link href="https://www.angelcruz.dev/til.xml" rel="self" type="application/rss+xml"/>
    <item>
      <title>IndexNow no acelera la indexación en Google</title>
      <link>https://www.angelcruz.dev/lab#indexnow-no-sirve-para-google</link>
      <guid isPermaLink="true">https://www.angelcruz.dev/lab#indexnow-no-sirve-para-google</guid>
      <description>Es el malentendido del protocolo: se implementa creyendo que avisa a Google, y Google no lo usa. Mueve Bing, Yandex, Seznam y Naver. Para Google el canal sigue siendo el sitemap con su `lastmod` y la inspección de URL en Search Console. Tampoco son 100 URLs al día, otro número que se repite: acepta 10.000 por POST y no publica cuota diaria.</description>
      <pubDate>Sat, 15 Aug 2026 00:00:00 GMT</pubDate>
      <author>Angel Cruz</author>
    </item>
    <item>
      <title>La URL que más necesitas reenviar a IndexNow es la que acabas de borrar</title>
      <link>https://www.angelcruz.dev/lab#indexnow-origen-de-un-redirect</link>
      <guid isPermaLink="true">https://www.angelcruz.dev/lab#indexnow-origen-de-un-redirect</guid>
      <description>Al consolidar dos posts en uno, la que hay que reenviar es la vieja: es la única forma de que el motor la rastree y vea el redirect. Y es justo la que ningún script te va a dar, porque la lista suele derivarse del directorio de contenido y esa carpeta ya no existe. Hay que pasarla a mano. Segunda trampa del mismo día: enviar antes de que el deploy salga hace que el motor revalide y reconfirme la versión vieja.</description>
      <pubDate>Sat, 15 Aug 2026 00:00:00 GMT</pubDate>
      <author>Angel Cruz</author>
    </item>
    <item>
      <title>requestAnimationFrame no dispara en pestañas de fondo</title>
      <link>https://www.angelcruz.dev/lab#requestanimationframe-pestanas-de-fondo</link>
      <guid isPermaLink="true">https://www.angelcruz.dev/lab#requestanimationframe-pestanas-de-fondo</guid>
      <description>Un aviso que se muestra con `requestAnimationFrame` dentro de un `useEffect` no aparece nunca si la pestaña se abrió en segundo plano: el navegador pausa `rAF` en documentos no visibles y lo reanuda recién cuando los miras. Si el `rAF` solo estaba para diferir un `setState` un tick y evitar el cascading-render, `setTimeout(fn, 0)` hace lo mismo y sí corre sin foco.</description>
      <pubDate>Tue, 04 Aug 2026 00:00:00 GMT</pubDate>
      <author>Angel Cruz</author>
    </item>
    <item>
      <title>pnpm 10 en CI ignora en silencio los ajustes de pnpm 11</title>
      <link>https://www.angelcruz.dev/lab#pnpm-10-ci-ignora-ajustes-de-pnpm-11</link>
      <guid isPermaLink="true">https://www.angelcruz.dev/lab#pnpm-10-ci-ignora-ajustes-de-pnpm-11</guid>
      <description>`allowBuilds` y `minimumReleaseAge` viven solo en `pnpm-workspace.yaml` y solo los lee pnpm 11; el campo `pnpm` de `package.json` ya no sirve para esto. Si el runner sigue en `pnpm/action-setup` con `version: 10` no falla nada: los ignora sin avisar, así que esbuild se queda sin su postinstall y Vitest sin transformador, con un error que no apunta a la causa.</description>
      <pubDate>Tue, 04 Aug 2026 00:00:00 GMT</pubDate>
      <author>Angel Cruz</author>
    </item>
    <item>
      <title>minimumReleaseAgeExclude de pnpm acumula en vez de reemplazar</title>
      <link>https://www.angelcruz.dev/lab#pnpm-minimumreleaseageexclude-acumula</link>
      <guid isPermaLink="true">https://www.angelcruz.dev/lab#pnpm-minimumreleaseageexclude-acumula</guid>
      <description>pnpm 11 trae `minimumReleaseAge` en 1440 minutos por defecto, así que rechaza cualquier versión publicada hace menos de un día. Al forzar la instalación añade la excepción sola a `minimumReleaseAgeExclude`, pero la acumula sobre la entrada vieja en lugar de sustituirla: queda `next@16.2.12 || 16.3.0` aunque la 16.2.12 ya no se instale. Solo hacen falta mientras la versión está dentro del corte, así que conviene podarlas.</description>
      <pubDate>Tue, 04 Aug 2026 00:00:00 GMT</pubDate>
      <author>Angel Cruz</author>
    </item>
    <item>
      <title>Chrome pinta el anillo de foco de un SVG en :focus, no en :focus-visible</title>
      <link>https://www.angelcruz.dev/lab#chrome-anillo-de-foco-svg-focus-visible</link>
      <guid isPermaLink="true">https://www.angelcruz.dev/lab#chrome-anillo-de-foco-svg-focus-visible</guid>
      <description>Un `&lt;path tabindex=&quot;0&quot;&gt;` enfocado con un clic da `:focus` pero no `:focus-visible`, y aun así Chrome le pinta `outline: auto`. Con `&lt;button&gt;`, `&lt;a&gt;` o un `&lt;div tabindex=&quot;0&quot;&gt;` no pasa. El reset va en `:focus { outline: none }`, no en `:focus-visible`; en Tailwind, la variante `focus:` y no `focus-visible:`.</description>
      <pubDate>Sat, 01 Aug 2026 00:00:00 GMT</pubDate>
      <author>Angel Cruz</author>
    </item>
    <item>
      <title>new Date() parsea la fecha sin hora como UTC y con hora como local</title>
      <link>https://www.angelcruz.dev/lab#new-date-utc-vs-local-segun-la-hora</link>
      <guid isPermaLink="true">https://www.angelcruz.dev/lab#new-date-utc-vs-local-segun-la-hora</guid>
      <description>`new Date(&apos;2026-08-01&apos;)` es medianoche UTC, pero `new Date(&apos;2026-08-01T00:00:00&apos;)` es medianoche local: añadir la hora cambia la zona. Si encima formateas con `Intl` sin fijar `timeZone`, la fecha sin hora retrocede un día en cualquier zona al oeste de UTC.</description>
      <pubDate>Sat, 01 Aug 2026 00:00:00 GMT</pubDate>
      <author>Angel Cruz</author>
    </item>
    <item>
      <title>Laravel 13: Context::add() comparte datos entre middlewares y jobs</title>
      <link>https://www.angelcruz.dev/lab#laravel-13-context-add-middlewares-y-jobs</link>
      <guid isPermaLink="true">https://www.angelcruz.dev/lab#laravel-13-context-add-middlewares-y-jobs</guid>
      <description>El nuevo helper `Context` en Laravel 13 permite pasar metadata a lo largo del request sin pasar parámetros. Útil para tracing: `Context::add(&apos;request_id&apos;, $id)` en un middleware y luego `Context::get(&apos;request_id&apos;)` desde cualquier job en cola. Persiste automáticamente al despachar jobs.</description>
      <pubDate>Fri, 15 May 2026 00:00:00 GMT</pubDate>
      <author>Angel Cruz</author>
    </item>
    <item>
      <title>PHP 8.4: Property hooks reemplazan getters y setters</title>
      <link>https://www.angelcruz.dev/lab#php-8-4-property-hooks</link>
      <guid isPermaLink="true">https://www.angelcruz.dev/lab#php-8-4-property-hooks</guid>
      <description>PHP 8.4 introduce property hooks nativos. En vez de definir `getName()` y `setName()`, escribes `public string $name { get =&gt; ucfirst($this-&gt;_name); set =&gt; $this-&gt;_name = trim($value); }`. Menos boilerplate y API más limpia para value objects y DTOs.</description>
      <pubDate>Tue, 12 May 2026 00:00:00 GMT</pubDate>
      <author>Angel Cruz</author>
    </item>
    <item>
      <title>@starting-style permite animar elementos al aparecer en el DOM</title>
      <link>https://www.angelcruz.dev/lab#starting-style-animar-al-aparecer</link>
      <guid isPermaLink="true">https://www.angelcruz.dev/lab#starting-style-animar-al-aparecer</guid>
      <description>La regla CSS `@starting-style` define el estado inicial de un elemento antes de la primera renderización. Útil para animaciones de entry sin JS: define los valores iniciales dentro de `@starting-style { ... }` y los finales en la regla normal. Soportado en Chrome 117+ y Safari 17.5+.</description>
      <pubDate>Fri, 08 May 2026 00:00:00 GMT</pubDate>
      <author>Angel Cruz</author>
    </item>
    <item>
      <title>View Transitions API funciona cross-document en Chrome 126+</title>
      <link>https://www.angelcruz.dev/lab#view-transitions-cross-document</link>
      <guid isPermaLink="true">https://www.angelcruz.dev/lab#view-transitions-cross-document</guid>
      <description>Las View Transitions ya no son solo para SPAs. Con `@view-transition { navigation: auto; }` en el CSS, Chrome 126+ aplica transiciones automáticas entre navegaciones MPA. Esto significa transiciones suaves en sitios estáticos sin necesidad de un framework JS.</description>
      <pubDate>Mon, 04 May 2026 00:00:00 GMT</pubDate>
      <author>Angel Cruz</author>
    </item>
    <item>
      <title>Next.js 16: &apos;use cache&apos; + cacheLife() reemplaza configuración fetch</title>
      <link>https://www.angelcruz.dev/lab#next-16-use-cache-cachelife</link>
      <guid isPermaLink="true">https://www.angelcruz.dev/lab#next-16-use-cache-cachelife</guid>
      <description>Con Cache Components habilitado, marcar una función con `&apos;use cache&apos;` y opcionalmente `cacheLife(&apos;hours&apos;)` reemplaza el viejo `fetch(url, { next: { revalidate } })`. Más declarativo y funciona con cualquier fuente de datos, no solo fetch. PPR genera shells estáticos + streaming dinámico.</description>
      <pubDate>Thu, 30 Apr 2026 00:00:00 GMT</pubDate>
      <author>Angel Cruz</author>
    </item>
    <item>
      <title>Next.js revalidateTag() requiere expire: 0 para invalidación inmediata</title>
      <link>https://www.angelcruz.dev/lab#next-revalidatetag-expire-0</link>
      <guid isPermaLink="true">https://www.angelcruz.dev/lab#next-revalidatetag-expire-0</guid>
      <description>Descubrí que `revalidateTag(tag)` en Next.js 16 no invalida inmediatamente por defecto. Debes usar `revalidateTag(tag, { expire: 0 })` para forzar invalidación inmediata del cache. Esto es crítico para webhooks de revalidación.</description>
      <pubDate>Thu, 29 Jan 2026 00:00:00 GMT</pubDate>
      <author>Angel Cruz</author>
    </item>
    <item>
      <title>OKLCH es superior a HSL para dark mode</title>
      <link>https://www.angelcruz.dev/lab#oklch-vs-hsl-en-dark-mode</link>
      <guid isPermaLink="true">https://www.angelcruz.dev/lab#oklch-vs-hsl-en-dark-mode</guid>
      <description>OKLCH (color space) mantiene la percepción de brillo constante entre colores, a diferencia de HSL. Esto significa que un color con L=0.5 en OKLCH se verá igualmente brillante que cualquier otro color con L=0.5, perfecto para sistemas de diseño consistentes en dark mode.</description>
      <pubDate>Wed, 28 Jan 2026 00:00:00 GMT</pubDate>
      <author>Angel Cruz</author>
    </item>
    <item>
      <title>React.cache() deduplica requests en Server Components</title>
      <link>https://www.angelcruz.dev/lab#react-cache-deduplica-requests</link>
      <guid isPermaLink="true">https://www.angelcruz.dev/lab#react-cache-deduplica-requests</guid>
      <description>Usar `cache()` de React en funciones de data fetching en Next.js App Router deduplica automáticamente requests idénticos durante el mismo render tree. Ejemplo: si 3 componentes llaman a `getPost(&apos;slug-123&apos;)`, solo se ejecuta 1 request.</description>
      <pubDate>Tue, 27 Jan 2026 00:00:00 GMT</pubDate>
      <author>Angel Cruz</author>
    </item>
    <item>
      <title>Tailwind @theme inline reemplaza extend en v4</title>
      <link>https://www.angelcruz.dev/lab#tailwind-theme-inline-en-v4</link>
      <guid isPermaLink="true">https://www.angelcruz.dev/lab#tailwind-theme-inline-en-v4</guid>
      <description>En Tailwind CSS v4, `@theme inline` es la nueva forma de extender el tema. Reemplaza `theme: { extend: {} }` de v3. Mejora el performance del build y permite CSS variables nativas.</description>
      <pubDate>Mon, 26 Jan 2026 00:00:00 GMT</pubDate>
      <author>Angel Cruz</author>
    </item>
    <item>
      <title>AVIF reduce imágenes 50% vs WebP</title>
      <link>https://www.angelcruz.dev/lab#avif-vs-webp-peso-de-imagenes</link>
      <guid isPermaLink="true">https://www.angelcruz.dev/lab#avif-vs-webp-peso-de-imagenes</guid>
      <description>AVIF logra la misma calidad visual que WebP con ~50% menos tamaño de archivo. Para Next.js, configurar `formats: [&apos;image/avif&apos;, &apos;image/webp&apos;]` como fallback es la mejor estrategia. Safari soporta AVIF desde v16.4.</description>
      <pubDate>Sun, 25 Jan 2026 00:00:00 GMT</pubDate>
      <author>Angel Cruz</author>
    </item>
    <item>
      <title>adjustFontFallback previene CLS en font loading</title>
      <link>https://www.angelcruz.dev/lab#adjustfontfallback-previene-cls</link>
      <guid isPermaLink="true">https://www.angelcruz.dev/lab#adjustfontfallback-previene-cls</guid>
      <description>Next.js tiene `adjustFontFallback: true` en next/font que ajusta métricas del fallback font para match el custom font, previniendo layout shift (CLS) durante la carga. Crítico para Core Web Vitals.</description>
      <pubDate>Sat, 24 Jan 2026 00:00:00 GMT</pubDate>
      <author>Angel Cruz</author>
    </item>
  </channel>
</rss>