← На главную

zserge собрал htmx-клон: ядро 40 строк (scan, send, swap) и плагины

31.07.2026 05:16 · hackernews

Автор блога zserge собрал минимальный работающий клон htmx менее чем в сотне строк — и заодно показал, как наращивать фичи плагинами, не трогая ядро. Эксперимент стартует с идеи: зачем фронтендеру JavaScript, если бэкенд и так отдаёт готовый HTML? Библиотека-замена по сути сводится к трём шагам — scan, send, swap.

В основе лежит обход DOM: все элементы с атрибутами x-get, x-post, x-put, x-patch, x-delete получают слушатели событий. По умолчанию для форм это submit, для полей ввода — change, для кнопок — click. Функция swap() умеет заменять (outerHTML), вставлять до и после (beforebegin, afterbegin, beforeend, afterend) и удалять целевой элемент — достаточно одного <template> для безопасной вставки HTML. Вызов fetch идёт с заголовком HX-Request: true, а если элемент — форма, собираются FormData. Так получается ядро в 40 строк.

Дальше автор добавляет парсинг продвинутых триггеров через x-trigger: можно перечислить события через запятую, задавать модификаторы вроде once, changed, delay:500 и load. Резолвер целей resolve() учится понимать не только CSS-селекторы, но и this, next, previous, closest .container, find .something, body, window. Всё это позволяет строить декларативное поведение без расчёта на глобальный querySelector.

Поток запроса превращается в конвейер из четырёх кастомных событий на самом элементе: x:beforeSend, x:afterSend, x:beforeSwap и x:afterSwap. Каждое несёт детали запроса, и обработчики могут менять цель, режим замены или вовсе отменять действие через preventDefault(). Серверная часть отвечает не только HTML: заголовки HX-Trigger рассылают произвольные события на document.body, а HX-Redirect и HX-Refresh управляют навигацией. Заголовки HX-Retarget и HX-Reswap переопределяют цель и способ замены «на лету». После каждой подмены контента MutationObserver вызывает scan() только для свежих узлов, чтобы не пересканировать всё дерево.

На этом ядро останавливается, а всё остальное автор выносит в плагины — короткие сниппеты, которые вешаются на события. Например, x-boost перехватывает клики по ссылкам и отправляет AJAX вместо полной перезагрузки страницы. x-confirm показывает нативный confirm() в x:beforeSend. x-indicator показывает спиннер на время запроса, а x-disable блокирует кнопку от двойной отправки. Появляются x-vals и x-include для подмешивания данных в тело запроса, x-select для замены только фрагмента ответа, x-sync для контроля одновременных запросов, x-validate для браузерной валидации форм и x-push-url с history.pushState. Даже Server-Sent Events и WebSockets можно прикрутить отдельно, дёргая swap() напрямую из onmessage.

Никакой из этих плагинов не требует лезть в код x.js — всё держится на событиях и трёх китах: scan, send, swap. Полный исходник лежит на GitHub (zserge/x). Автор признаёт, что до полноценной совместимости с htmx не хватает обработки ошибок fetch, обещаний для асинхронных диалогов и View Transitions, но называет это упражнением для читателя — или поводом всё-таки взять оригинал.

Читать оригинал →