Всем привет! В данной статье рассмотрим такой javascript модуль как HMPL и как он может заменить HTMX в проекте. Также, рассмотрим в чём их отличия, преимущества и недостатки.

При дальнейшем сравнение двух модулей стоит учесть, что один является языком шаблонов, когда как другой является набором инструментов для работы с HTML, реализуемых через атрибуты и не только.

Начнём с общей концепции для двух модулей.

Концепция сокращения javascript кода путём выноса компонентов пользовательского интерфейса на сервер

Модуль HMPL схож по концепции с HTMX. Мы также можем брать HTML с сервера по API, заменяя тем самым современные фреймворки и библиотеки для создания UI. Возьмём небольшой пример, иллюстрирующий работу HMPL и HTMX, а также такого фреймворка как Vue.js:

Vue.js пример:

createApp({
  setup() {
    const count = ref(0);
    return {
      count,
    };
  },
  template: `<div>
        <button @click="count++">Click!</button>
        <div>Clicks: {{ count }}</div>
    </div>`,
}).mount("#app");

Size: 226 bytes (4KB on disk)

HMPL пример:

document.querySelector("#app").append(
  hmpl.compile(
    `<div>
        <button>Click!</button>
        <div>Clicks: {{ "src": "/api/clicks", "after": "click:button" }}</div>
    </div>`
  )().response
);

Size: 206 bytes (4KB on disk)

HTMX пример:

<div>
  <button hx-post="/api/increment" hx-target="#counter" hx-swap="outerHTML">Click!</button>
  <div id="counter">Clicks: 0</div>
</div>

140 bytes (4 KB on disk)

На примере простого кликера можно увидеть (с небольшими оговорками по данным на стороне сервера и на стороне клиента, а также по html и js разметке, но не в это главная идея), что мы получаем одинаковый интерфейс, хотя размеры файлов на клиенте будут совершенно разными. В этом как раз и основное преимущество подхода создания уже готового, или шаблонного компонента UI на стороне сервера, чтобы пользователь сайта загружал его быстрее с сохранением результата.

Теперь, вспомним, насколько большие приложения сегодня, ну, или по крайней мере раньше (когда server-side rendering не был ещё настолько популярным), могли получаться при использовании фреймворков и библиотек. Тот же SPA (Single Page Application), генерирует весь контент через javascript, когда в html у нас буквально одна строчка, но в том и прикол, что при 10 килобайтном html мы получаем javascript файл размером в несколько десятков мегабайт. Такой сайт, первом заходе, пользователи могут грузить долго.

К примеру, если потенциальный клиент захочет по быстрому заказать себе цветы, то он не будет ждать 10-15 секунд, пока сайт магазина доставки прогрузится, он перейдёт на другой сайт, где сайт будет грузиться быстрее.

Есть ещё много прикладных примеров работы сайтов, которые могут влиять на воронку продаж. Но, суть в том, что главное - это скорость и удобство интерфейса, а вот тут уже есть различия в подходах. Но, лучше сделать это в отдельной статье. Тут же рассматривается сравнение HMPL и HTMX.

Зачем использовать HMPL и в чём его преимущества перед HTMX?

В данном разделе постараюсь рассказать про несколько основных причин, по которым вы можете выбрать, в некоторых случаях, HMPL вместо HTMX:

При схожей идее сокращения кода, два модуля отличаются в понятиях. В случае HTMX, с одной стороны, мы получаем удобный инструментарий работы с уже существующим DOM, но с другой, всё это происходит через HTML и обновляется буквально в режиме реального времени. Мы с большим трудом, через нетипичиные решения, можем работать более ли менее через javascript, а по сути, работа с javascript почти полностью отсутствует. В случае HMPL, с одной стороны, мы без труда можем работать с javascript; генерировать кастомный RequestInit, создавать тысячи отдельных DOM узлов с той же поддержкой серверного UI, что и на HTMX, но с другой - всё таки работа происходит с кодом, что не всегда удобно, когда хочется создавать проекты быстрее. Возьмём пример кода:

HMPL пример:

import { compile ) from "hmpl-js";

const templateFn = compile(
  `<div>
  <form onsubmit="function prevent(e){e.preventDefault();};return prevent(event);" id="form">
    <div class="form-example">
      <label for="name">Enter your email: </label>
      <input type="text" name="email" id="email" required />
    </div>
    <div class="form-example">
      <input type="submit" value="Register!" />
    </div>
  </form>
  <p>Email {
    {
      "src":"/api/register",
      "after":"submit:#form",
    }
  } successfully registered!</p>
</div>`
);
const initFn = (ctx) => {
  const event = ctx.request.event;
  
  return {
    body: new FormData(event.target, event.submitter),
    credentials: "same-origin"
  };
};
const obj = templateFn(initFn);
wrapper.appendChild(obj.response);

HTMX пример:

<script src="/path/to/htmx.min.js"></script>
<div>
  <form hx-post="/api/register" hx-target="#notification" hx-swap="outerHTML">
    <div class="form-row">
      <label for="name">Enter your email: </label>
      <input type="text" name="email" id="email" required />
    </div>
    <div class="form-row">
      <input type="submit" value="Register!" />
    </div>
  </form>
  <p id="notification"></p>
</div>

На данном примере чётко видно, что HTMX - это больше про максимальное убыстрение и укорачивание кода, когда как HMPL - это нечто комбинированное между HTMX и современным фреймворком или библиотекой для создания UI. Можно сказать, что мы получаем несколько похожий результат, но с учётом того, что мы можем кастомизировать запрос на сервер.

Синтаксис HMPL тоже является в своём роде преимуществом, потому что объекты запроса не привязаны к какому-либо тегу. При рендеринге они заменяются на коментарии, которые не засоряют DOM ненужными тегами. Пример синтаксиса:

HMPL полностью построен на fetch заросах, которые ввели как стандарт в 2015 году. HTMX для поддержки IE13 по дефолту использует XMLHTTPRequest, который был введён в 2000 году. Функция fetch позволяет использовать современные возможности javascript в браузерах, такие как AbortController, signals и другое

И, есть ещё достаточное количество преимуществ, по типу отдельного расширения файла .hmpl при работе с вебпаком и другие, но, на мой взгляд, те, которые я выделил, являются наиболее важными. Вебпак конфиг:

Недостатки HMPL

Также, у hmpl есть ряд недостатков, о которых мне бы хотелось рассказать:

У HMPL пока нету поддержки WebSocket, что может усложнить внедерение кода в проект. В HTMX данная поддержка присутствует.

Так как происходит использование fetch, то в некоторых старых версиях браузера вёрстка поддерживаться не будет.

HTMX - это годами протестированная технология, когда как HMPL - это новый модуль.

Вывод

Язык шаблонов HMPL может заменить HTMX в тех случаях, когда требуется гибкая настройка запроса, а также непосредственная работа с узлами через javascript; Если вы, допустим, хотите создать цикл из 1000 одинаковых узлов, и при этом иметь преимущества серверо-ориентированного UI, то он также подойдёт для задачи. Если же цель стоит в полной минимизации работы с javascript, либо же в использовании устоявшегося протестированного модуля и простым подключением к серверу с минимальным количеством HTML кода, то тут HTMX хорош.

Ссылки:

https://hmpl-lang.github.io

https://htmx.org

Комментарии (9)


  1. alpatovdanila
    17.10.2024 09:37

    Можете, пожалуйста, объяснить зачем вообще нужен htmx? Мы все последние 20 лет вешали атрибуты на элементы и обрабатывали их через жс (можно даже было собрать это в 1 файл и сказать что это библиотека), но потом пришло понимание что хтмл просто не очень хорошо подходит для шаблонизации и в целом для описания императивной логики, которая в любом случае всегда нужна в реальной жизни. К тому же в HTMX все равно есть идиоматические способы писать вещи на жс. А для чего это все тогда?


    1. antonmak1 Автор
      17.10.2024 09:37

      Для сокращения размеров файлов, скачиваемых на клиенте. От этого всё идёт. Условно, скачать 1 мб HTML и потом 20 мб с css и html с сервера быстрее, чем 21 мб сразу качать.


      1. alpatovdanila
        17.10.2024 09:37

        1мб хтмл и потом стили и жс - это же то что происходит сейчас при использовании любого фреймворка. Как раз htmx должен раздувать html потому что теперь в нем дополнительные атрибуты и "код"


    1. antonmak1 Автор
      17.10.2024 09:37

      Но, есть много ньюансов с кешированием, клиентскими данными, быстротой разработки и другим. Это просто быстрый ответ на вопрос.


  1. Genrehopper
    17.10.2024 09:37

    очередная замена "ххх", который сам является заменой "yyy"


  1. ilya_chch
    17.10.2024 09:37

    Мне кажется, автор не понимает, зачем и как использовать htmx. И примеры некорректны.

    Первый пример на vue показывает инкремент на клиенте. Про HMPL не скажу, но htmx подразумевает обновление на бэке. При этом не понятно, зачем hx-get="/api/clicks" на div - какое действие должно триггернуть это?
    Во втором примере - тоже не верное использование. Опять непонятный hx-get="/api/registeredEmail" на span, который так же ничем не будет вызван. Еще и onsubmit="function prevent(e){e.preventDefault();};return prevent(event);" id="form"> зачем-то.

    Первый пример должен быть примерно таким:

    <div>
      <button hx-post="/api/increment" hx-target="#counter" hx-swap="outerHTML">Click!</button>
      <div id="counter">Clicks: 0</div>
    </div>
    

    и в зависимости от ответа бэка на такой запрос может меняться hx-swap - outerHTML, если возвращается <div id="counter">Clicks: {{count}}</div>, либо innerHTML если бэк отвечает просто Clicks: {{count}}

    Второй пример должен быть таким:

    <script src="/path/to/htmx.min.js"></script>
    <div>
      <form hx-post="/api/register" hx-target="#notification" hx-swap="outerHTML">
        <div class="form-row">
          <label for="name">Enter your email: </label>
          <input type="text" name="email" id="email" required />
        </div>
        <div class="form-row">
          <input type="submit" value="Register!" />
        </div>
      </form>
      <p id="notification"></p>
    </div>
    

    И бэк должен ответить <p id="notification">Email {{ email }} successfully registered!</p>.

    Смысл HTMX мне видится не в замене реактивных клиентских фреймворков (про сравнение с vue), а упрощение SSR (возврат к концепции, когда все рендерится на бэке), упрощении взаимодействия бэка и фронта и добавлении интерактивности. Понятно, что какой-нибудь draw.io не сделаешь на HTMX, но для какого-нибудь не сильно сложного сайта (тот же хабр) зачем тянуть какой-нибудь frontend framework или библиокету?


    1. antonmak1 Автор
      17.10.2024 09:37

      Поправил примеры с HTMX - спасибо! По поводу того, что не знаю, зачем HTMX использовать, может оно и так. Если работать с сервером, то иногда требуются дополнительные настройки, современные функци, идующие с fetch, и ещё плюшки работы с javascript и DOM деревом. HTMX упрощает в этом смысле работу с сервером, что всего по минимуму, но на практике, когда хочется чего-то большего, то библиотека выдаёт свой потолок вот этими упрощениями.


      1. ilya_chch
        17.10.2024 09:37

        Если работать с сервером, то иногда требуются дополнительные настройки, современные функци, идующие с fetch, и ещё плюшки работы с javascript и DOM деревом

        Например?

        Я не говорю, что HTMX должен заменить библиотеки и фреймворки. Я считаю, что разные инструменты нужны для разных вещей. Для минимального манипулирования DOM яв предпочитаю использовать hyperscript (от автора HTMX и неплохой интеграции с ним) или alpineJS.

        Текущий подход с отдельным бэком и фронтом на React/Vue/Angular/Svelte/etc... позволяет более гибко управлять командами, разделяя ответственность, строя независимые циклы релизов и прочее. Но у этого есть цена - переусложнение (отдельный пайплайн сборки фронта, отдельные настройки для SSR, backend-for-frontend простихоспади), проблема синхронизации и передачи состояний (раньше состояние хранилось и управлялось на бэке). И некоторые функции в текущих фреймворках выглядят как решения проблем, которые были искусственно созданы. Ну и порой неадекватный размер фронтовых бандлов - туда же.

        Для того, чтобы отобразить просто список статей/статью, табличку, обработать форму - вовсе не обязательно строить второе приложение.
        Это, само собой, не касается приложений, которые полностью работают на фронте (тот же draw.io, google docs, всякие игры и прочее).
        Если правильно разбить html на бэке (на переиспользуемые компоненты) - работа с htmx не доставляет головной боли=)

        При этом, в случае с HMPL - если я правильно понял, это все равно отдельный JS файл (или файлы), который с нуля строит страницу. Концептуально, он выглядит более похожим на фреймворки большой тройки. И получается вообще все будет в бандле, даже элементы страниц, которые на данный момент не нужны. Понятно, что можно как-то настроить бандлер и подгрузку модулей, чтобы грузилось только то, что нужно на текущий момент, но это не просто и выглядит как решение выдуманной проблемы.

        В целом, я категорически не согласен с мыслью:

        Модуль HMPL схож по концепции с HTMX


  1. toxadx
    17.10.2024 09:37

    Сравнение некорректное, т.к. автор не понимает концепцию HTMX, а рассуждает привычными концепциями.
    Для понимания концепции HTMX рекомендую бесплатную книжку - https://hypermedia.systems/book/contents/