Inicio / Artículos / Actualización a htmx 4: Fetch, herencia explícita y qué se rompe

Actualización a htmx 4: Fetch, herencia explícita y qué se rompe

Comprenda los cambios en la arquitectura de htmx 4, desde el núcleo basado en Fetch y la herencia explícita de atributos hasta los intercambios de errores, el morphing y el historial, y planifique una migración segura.

2717 palabras

Htmx se basa en una apuesta sencilla y deliberadamente anticuada: el servidor devuelve HTML, el navegador lo inserta en la página y surge una aplicación funcional sin necesidad de replicar toda la interfaz como estado del lado del cliente. La versión 4 mantiene esa apuesta intacta mientras reconstruye los mecanismos subyacentes utilizando las primitivas de los navegadores modernos. Esta guía explica qué cambió y por qué, qué cambios pueden dañar silenciosamente una aplicación existente, y cómo realizar la actualización como un proceso de auditoría estructurado en lugar de simplemente un aumento de versión. Los detalles reflejan a htmx 4 tal como estaba documentado en el momento de redactar este texto; confirme los aspectos específicos consultando las notas de la versión actual antes de migrar.

El contrato que mantiene htmx 4

Es útil recordar qué reemplaza Htmx. Una aplicación típica renderizada en el cliente solicita JSON a una API, almacena esos datos en JavaScript, renderiza componentes a partir de ellos y reconcilia continuamente el estado local con el servidor. Htmx elimina la mayor parte de esa capa intermedia. El servidor responde con la representación que realmente necesita el usuario, que es HTML.

Considere un botón anotado con atributos como hx-post, un destino como #task-list y una estrategia de inserción por anexión. Cuando alguien lo hace clic, Htmx recopila el contexto de la solicitud, lo envía al servidor, analiza el marcado que regresa y lo anexa a la lista de tareas. La validación, autorización, persistencia y presentación permanecen en el servidor. La interacción, navegación, enfoque y el propio documento quedan en el navegador.

Eso es más que una forma concisa de denominar a fetch(). Los atributos describen un control hipermedia: qué acción está disponible, a dónde se envía y cómo la representación resultante debe integrarse en la página actual. El fragmento que regresa puede contener, a su vez, enlaces y formularios que anuncian las próximas acciones válidas, exactamente como lo haría una página completa. En otras palabras, HTML sigue siendo el protocolo de aplicación; htmx simplemente coordina el proceso de ida y vuelta.

La versión 4 mantiene esa superficie pública prácticamente estable de forma monótona. Lo que reorganiza es el ciclo de vida subyacente; el resultado no es un nuevo framework front-end, sino reglas más estrictas sobre cómo colaboran HTML, HTTP, el DOM y el servidor que gestiona el estado.

Un núcleo reconstruido sobre la Fetch API

Las versiones anteriores dependían de XMLHttpRequest. Eso tenía sentido cuando htmx tenía que funcionar en navegadores más antiguos, y XHR ofrecía eventos de progreso de carga de los que dependían algunas aplicaciones. Con el tiempo, sin embargo, esa decisión por la compatibilidad se convirtió en una deuda arquitectónica. El equipo de htmx reescribió la lógica de solicitud utilizando la API Fetch basada en promesas, inspirándose en experimentos con un proyecto relacionado más pequeño llamado Fixi y en el HTML de transmisión en tiempo real.

Un esquema predecible para nombrar eventos

El flujo más ordenado se refleja en el modelo de eventos. Ahora los nombres de los eventos siguen un patrón consistente, htmx:phase:action, que opcionalmente se puede extender con una subacción (htmx:phase:action:sub-action). Dado que la fase viene primero, se puede saber de inmediato si un listener se dispara antes o después del paso al que hace referencia.

Cada evento relacionado con una solicitud también recibe el mismo objeto de contexto. Las extensiones y los listeners ya no tienen que reunir una serie de detalles específicos del evento para encontrar el elemento fuente, la configuración de la solicitud, la respuesta y el intercambio pendiente; todo está en un mismo lugar. Las solicitudes también cuentan con una fase finally que se activa independientemente del resultado: éxito, fracaso o cancelación. Ese es el lugar adecuado para tareas de limpieza como ocultar indicadores de carga o volver a habilitar botones.

Si su base de código escucha eventos htmx por nombre, cada listener necesita ser revisado, ya que los nombres antiguos no coinciden con el nuevo esquema.

Envoltorios obsoletos en favor de la plataforma

Htmx 4 también elimina las funciones auxiliares que duplicaban APIs que los navegadores ahora proporcionan de forma fiable:

  • htmx.addClass() da paso a element.classList.add()
  • htmx.closest() ha sido reemplazado por element.closest()
  • htmx.remove() ha sido reemplazado por element.remove()
  • Se trata de una sustitución positiva. Una librería pequeña no debería seguir utilizando APIs prácticas indefinidamente una vez que la plataforma ya las ha incorporado, y los reemplazos son llamadas estándar al DOM que cualquier desarrollador ya conoce.

    La herencia de atributos ahora es opcional

    El cambio más significativo en esta migración no tiene nada que ver con Fetch. Htmx 4 deja de heredar implícitamente la mayoría de los atributos de los elementos ancestros.

    Anteriormente, un atributo aplicado a un contenedor, como por ejemplo un destino, un mensaje de confirmación o un conjunto de encabezados de solicitud, se aplicaba silenciosamente a todos los descendientes gestionados por htmx. En la versión 4 es necesario declarar explícitamente ese alcance añadiendo el sufijo :inherited al nombre del atributo en el elemento padre. Un descendiente que desee extender un valor o selector heredado, en lugar de sobrescribirlo, puede utilizar el sufijo :append.

    Ese sufijo no es meramente decorativo. Indica a quien lea la plantilla que el atributo del padre forma parte intencionada del comportamiento de sus hijos. Esto acerca aún más a htmx al principio de localidad del comportamiento: cuanto más cerca esté una declaración del elemento al que se refiere, menos contexto invisible tendrá que reconstruir el lector. Aún es posible compartir comportamientos; su ámbito se anuncia simplemente donde se declara.

    Por qué esta es la parte más arriesgada de la actualización

    El cambio también genera un modo de fallo silencioso. Supongamos que siempre se ha definido un encabezado CSRF en el contenedor del diseño. Después de la actualización, la página se muestra exactamente como antes, pero las solicitudes provenientes de los elementos hijos ya no incluyen ese encabezado y comienzan a ser rechazadas por el servidor. No parece haber ningún problema hasta que alguien envía un formulario.

    Htmx ofrece una herramienta oficial de verificación de actualizaciones que escanea plantillas y scripts en busca de herencia implícita, nombres de eventos obsoletos, atributos eliminados y APIs desactualizadas. Utilice su informe como lista inicial, no como garantía, y luego pruebe los verdaderos caminos de solicitud, especialmente aquellos protegidos por encabezados, confirmaciones o destinos compartidos.

    Las respuestas de error se convierten en fragmentos intercambiables

    En Htmx 2, las respuestas con códigos de estado 4xx o 5xx no se intercambiaban por defecto. Htmx 4 invierte esta situación: intercambia todas las respuestas HTTP excepto 204 No Content y 304 Not Modified.

    Cuando diferentes familias de estado deben dirigirse a lugares distintos o seguir reglas de intercambio diferentes, el nuevo atributo hx-status permite configurar esto por cada clase de estado; por ejemplo, enviar errores de validación a un área de mensajes integrada mientras que los errores del servidor van a un banner a nivel de página.

    La verdadera consecuencia recae en el servidor. Cada respuesta de error debe ser ahora un fragmento válido para el elemento que la reciba. Un rastro completo de llamadas o un cuerpo de error en JSON se insertará en el DOM tal como está. Los códigos de estado mantienen su significado HTTP para los cachés, registros y clientes, mientras que el cuerpo HTML contiene la presentación e, idealmente, la siguiente acción que puede realizar el usuario, como un formulario corregido.

    Actualización de varias regiones desde una sola respuesta

    A menudo, una única operación del lado del servidor necesita modificar más de solo el elemento en el que hizo clic el usuario. Publicar un mensaje podría añadirlo a una línea de tiempo, incrementar un contador de mensajes no leídos y reemplazar el control de paginación. Htmx ha ofrecido desde hace tiempo soluciones para esto: los elementos en la respuesta marcados como out-of-band reemplazan a los elementos correspondientes en otras partes del documento.

    Htmx 4 añade una herramienta más explícita: el elemento <hx-partial>. Cada parte declara su propio destino y estrategia de intercambio, de modo que la respuesta se presenta como una lista de actualizaciones claramente identificadas.

    También está definido el orden de procesamiento. La respuesta principal se intercambia primero; las partes y los elementos externos siguen en el orden del documento. Esto fomenta que cada actualización tenga sentido por sí misma, en lugar de depender de efectos secundarios de un cambio anterior en el DOM dentro de la misma respuesta.

    Esto equivale a una orquestación ligera de respuestas. El servidor puede describir todas las consecuencias visibles de una operación en una sola respuesta, sin tener que devolver JSON y dejar que el código del cliente distribuya los campos entre los componentes.

    Intercambios de transformación que mantienen el estado del navegador activo

    Sustituir innerHTML es fácil de comprender, pero elimina el estado que posee el navegador. Un campo de texto puede perder su selección, el foco puede cambiar de lugar, un video puede reiniciarse y un elemento personalizado puede ser desmontado y recreado incluso cuando la mayor parte de su marcado permanece sin cambios.

    Htmx 4 incluye los modos de intercambio innerMorph y outerMorph, basados en una versión mejorada del algoritmo Idiomorph. En lugar de descartar el subárbol objetivo, un proceso de morph compara los nodos antiguos y nuevos y aplica el conjunto más pequeño posible de cambios razonables. Los nodos que coinciden mantienen su identidad, así como su foco, selección, posición de reproducción y estado interno.

    El morphing no es necesariamente la mejor opción. Para un fragmento simple, el reemplazo total suele ser más seguro y fácil de depurar. El morphing resulta útil cuando el destino contiene controles de formulario en tiempo real, elementos personalizados, medios o widgets de terceros cuya identidad es importante. Htmx también ofrece selectores para omitir nodos completos o solo sus hijos durante el morphing, lo cual es una forma práctica de proteger elementos con estado como un mapa incrustado o un editor de texto enriquecido.

    El principio general merece ser tenido en cuenta incluso fuera de htmx: el servidor decide qué debería ser el HTML, y el navegador conserva los objetos DOM físicos que deben sobrevivir a la transición.

    La transmisión en flujo vive en las extensiones, no en el núcleo

    Fetch proporciona a htmx una base mucho mejor para respuestas en streaming, pero el núcleo no impone un protocolo de streaming único a todos. En su lugar, htmx 4 incluye extensiones separadas y especializadas para Server-Sent Events, WebSockets y respuestas multipart.

    La extensión para multipart, hx-multipart, comprende cuerpos de tipo multipart/mixed y multipart/parallel. Cada parte puede contener HTML junto con sus propios encabezados de acción HX-*. Esto permite al servidor enviar un marcador temporal de inmediato y, a medida que se completan las tareas lentas, transmitir secciones adicionales de forma individual, todo ello sin necesidad de un bus de mensajes desarrollado manualmente en el lado del cliente.

    La elección entre ellas depende de la estructura del flujo de datos:

    • SSE es adecuado para actualizaciones ordenadas y unidireccionales enviadas desde el servidor.
    • WebSockets son adecuados para comunicación verdaderamente bidireccional.
  • Multipart es adecuado para una única operación HTTP que genera varias representaciones a lo largo del tiempo.
  • Todos los tres métodos se integran en la misma mecánica de intercambio, por lo que el resto de tu marcado no necesita saber qué transporte entregó un fragmento.

    Un modelo de extensiones más simple

    Mantener la transmisión en flujo fuera del núcleo mantiene este último pequeño, y a cambio los límites de las extensiones se han vuelto más potentes. Las extensiones en htmx 4 se registran directamente y pueden conectarse a las fases de solicitud, respuesta e intercambio. Para activar una basta con incluir su script; el atributo hx-ext ya no existe. Si deseas un límite estricto, la configuración te permite restringir qué nombres de extensiones están permitidos en un sitio.

    HCON: una notación compacta para opciones de atributos

    A medida que los atributos acumulaban opciones, htmx necesitaba una sintaxis menos engorrosa que JSON incrustado en el valor de un atributo. La solución es HCON, la notación de objetos de configuración de htmx. Permite pares clave-valor separados por espacios, flags sin formato como valores booleanos, números, cadenas entre comillas y claves con puntos para anidamiento.

    Todavía se acepta JSON, lo cual es conveniente cuando un servidor ya genera la configuración. HCON está orientado a marcados escritos a mano: lo suficientemente conciso como para ser escaneado, pero lo bastante estructurado como para que htmx no necesite un analizador ad hoc separado para cada atributo. La misma notación se utiliza en desencadenadores, modificadores de intercambio, configuración de solicitudes, encabezados, valores y el encabezado de respuesta HX-Location; por lo tanto, aprenderla una vez tiene beneficios en todas partes.

    hx-live para el estado del cliente que permanece

    Hypermedia no elimina toda la interactividad local. Se abre un menú desplegable antes de realizar cualquier solicitud. Un contador de caracteres se actualiza con cada tecla pulsada. Las pestañas, los widgets de revelación y las selecciones temporales suelen ser responsabilidad del navegador.

    La nueva extensión hx-live aborda esos casos con una capa de scripting pequeña centrada en el DOM. Ofrece un ayudante para consultas, selectores direccionales para encontrar elementos cercanos, utilidades del DOM, ayudantes asíncronos, acceso tipado a atributos y valores de datos, además de enlaces reactivos como :text, :class y :hidden.

    Su regla fundamental es de carácter filosófico: el DOM es el almacén de estado. Una expresión reactiva lee el estado de los elementos cercanos y actualiza la presentación correspondiente. Todo lo que es duradero permanece en el servidor y llega a la página como HTML, tal como ocurría antes.

    Considere hx-live como una válvula de alivio para tareas menores en la interfaz de usuario, y no como una invitación a desarrollar una segunda aplicación dentro del navegador. Úselo cuando de lo contrario tendría que escribir código repetitivo para manejar eventos en una interfaz temporal. Cuando el estado debe persistir tras la navegación, compartirse entre usuarios, aplicarse permisos o participar en transacciones, ese estado debe permanecer en el servidor.

    Navegación por historial: nueva carga en lugar de restauración de instantáneas

    Htmx 2 almacenaba las instantáneas del historial en localStorage. Restaurar una de ellas podía volver a cargar las mutaciones del DOM realizadas por scripts no relacionados, sin recuperar el estado en tiempo de ejecución de JavaScript que las generó. La página parecía interactiva, pero en realidad era un DOM fossilizado: los widgets se mostraban, pero no había conexiones detrás de ellos.

    Htmx 4 elimina ese caché predeterminado. Al navegar hacia atrás o hacia adelante, vuelve a cargar la página e intercambia el resultado por <body> o por un elemento de historial designado. Los encabezados adecuados de caché HTTP pueden hacer que esa solicitud sea prácticamente gratuita, al tiempo que proporcionan a los scripts un documento limpio en el que inicializarse.

    Las aplicaciones que realmente necesitan instantáneas locales pueden cargar la extensión hx-history-cache, la cual utiliza sessionStorage y hace que dicho comportamiento sea explícito. Este patrón se repite en toda la versión: una representación actualizada es lo predeterminado, mientras que la reconstrucción local es una funcionalidad opcional con nombre propio.

    Trate la migración como una auditoría de comportamiento

    La actualización más segura no consiste en un intercambio ciego de paquetes, sino en una revisión detallada de todos los lugares donde el comportamiento trasciende los límites del marcado. La mayoría de las páginas mantienen su marcado sin cambios; el trabajo se concentra en la herencia implícita, los listeners de eventos, el manejo de respuestas, el historial y las extensiones.

    Primero fije una versión exacta de htmx 4 y luego ejecute el comprobador oficial de actualización descrito en la documentación de migración. Trate los resultados en un orden que evite colisiones entre atributos con nombres nuevos:

    1. Cambie el nombre del antiguo hx-disable, que significaba “ignorar este subárbol”, a hx-ignore.
    2. Solo después cambie el nombre de hx-disabled-elt al nuevo hx-disable. Realizar estos dos pasos en el orden inverso podría convertir accidentalmente un atributo en el otro.
  • Agregue :inherited en todos los lugares donde un padre debe seguir influyendo en sus descendientes, prestando especial atención a los encabezados, confirmaciones, destinos e incluciones.
  • Actualice los nombres de los receptores de eventos y reemplace las funciones auxiliares eliminadas por APIs nativas del navegador.
  • Pruebe las respuestas 4xx y 5xx, ya que ahora se intercambian por defecto, y asegúrese de que cada una devuelva un fragmento coherente.
  • Pruebe cada hx-delete, el cual ya no envía los datos del formulario que lo contiene a menos que se solicite con hx-include.
  • Pruebe la navegación hacia atrás y hacia adelante, el orden fuera de banda, los tiempos de espera, las colas de solicitudes y cada extensión que utilice, teniendo en cuenta que hx-ext ya no existe.
  • Cuándo htmx 4 es la herramienta adecuada

    El cambio principal es “Fetch”, pero el tema unificador es la explicitud. Un atributo solo llega a sus descendientes cuando su declaración así lo indica. Por defecto, se muestra al usuario el HTML de una solicitud fallida, y usted configura las excepciones. Las respuestas que afectan varias regiones especifican dónde va cada parte y cómo se sustituye. La navegación hacia atrás y hacia adelante carga una página nueva, a menos que active deliberadamente un caché de instantáneas con nombre. Las extensiones se integran a través de un único ciclo de vida compartido, y los métodos estándar del DOM toman el control donde antes htmx utilizaba sus propios auxiliares.

    Juntos, estos elementos reducen el comportamiento oculto sin trasladar el estado de la aplicación a un framework del cliente. Ese es el equilibrio que busca htmx: interacción enriquecida, autoridad del servidor y un HTML que sigue describiendo qué puede hacer la página.

    No hará que todas las interfaces sean más simples. Un editor gráfico, un espacio de trabajo orientado a modo offline o una aplicación basada en un modelo local altamente colaborativo pueden justificar una arquitectura de cliente más compleja. Sin embargo, muchas aplicaciones empresariales se reducen principalmente a navegación, formularios, tablas, validación y flujos de trabajo que ya están gestionados por el servidor. En estos casos, devolver la representación final suele ser más sencillo que mantener sincronizadas dos máquinas de estado.

    Puntos clave

    • El modelo htmx no ha cambiado: los elementos son controles de hipermedia, las respuestas son HTML y el servidor gestiona el estado.
    • La herencia implícita de atributos ya no existe; la falta de sufijos :inherited es la causa más probable de fallos silenciosos, especialmente en los encabezados CSRF.
    • Las respuestas de error ahora se intercambian por defecto, por lo que cada cuerpo de respuesta 4xx y 5xx debe ser un fragmento válido para su destino.
  • <hx-partial> y los intercambios por transformación hacen que las actualizaciones en múltiples regiones y los intercambios que preservan el estado sean explícitos y predecibles.
  • La transmisión en flujo, la interactividad del lado del cliente y el caché de historial se trasladaron a extensiones opcionales, manteniendo el núcleo pequeño.
  • Ejecute el comprobador de actualizaciones y luego pruebe rutas de solicitud reales; el comprobador identifica posibles candidatos, pero solo las pruebas demuestran que la aplicación sigue funcionando.
  • Lecturas relacionadas