Почему я сделал Micra

·

Я помню время, когда jQuery стоял почти на каждом сайте. Тогда еще не было фреймворков и jQuery был простым способом дотянуться до DOM: навесить обработчик, что-то показать, что-то спрятать, дёрнуть запрос. Тогда это решало большинство задач. Потом фронтенд стал сложнее. Во многом по делу, потому что приложения выросли, и React, Vue, Svelte выросли вместе с ними. Но такая сложность нужна не всегда.

Осталось много проектов, где сервер уже отдаёт готовую HTML-разметку, а на клиенте требуется лишь немного реактивности: открыть модалку, обновить счётчик, отфильтровать таблицу, переключить вкладку. Разворачивать ради этого полноценный фреймворк со сборкой и роутингом часто не хочется. А писать на чистом JavaScript быстро становится неудобно, когда нужно отслеживать состояние и синхронизировать его с DOM.

Я искал решение, которое даёт реактивность, но при этом остаётся максимально лёгким и не требует отдельного билда. Хотелось просто подключить скрипт к уже существующей серверной разметке — и чтобы она начала реагировать на изменения состояния.

Основная идея

Micra позволяет сделать HTML, который пришёл с сервера, реактивным. Ты описываешь поведение в обычном JavaScript-объекте, а в разметке используешь простые data-атрибуты и директивы.

Вот как это выглядит:

<div data-component="modal">
<button @click="open">Открыть диалоговое окно</button>
<div data-show="isOpen">
<div class="backdrop" @click="close"></div>
<div role="dialog" aria-modal="true">
<h2>Пример диалогового окна</h2>
<button @click="close">Закрыть</button>
</div>
</div>
</div>

А поведение описывается обычным JS-объектом — методами и состоянием без отдельного слоя представления:

Micra.define("modal", {
state: {
isOpen: false,
},
open() {
this.state.isOpen = true;
},
close() {
this.state.isOpen = false;
}, // data-show прячет и показывает сам
});
Micra.start(); // найти на странице data-component и поднять их

Нажали кнопку — open() ставит isOpen = true, и блок с data-show="isOpen" появляется. Клик по «Закрыть» или по фону зовёт close() — он закрывает блок. Никаких ручных поисков элементов по querySelector и манипуляций со стилями. Изменилось только состояние, остальное взяла на себя библиотека.

В этом вся идея. Ты пишешь обычный HTML. Не нужно держать в голове дерево, выцеплять узлы по селекторам и руками сводить их с состоянием. Классы остаются тем, чем были, — для стилизации. А data-атрибуты говорят, что на этом куске разметки происходит: data-component — где живёт компонент, data-show — когда его показывать, @click — что вызвать по клику. Поведение описано прямо в разметке, а сама разметка остаётся читаемым HTML.

Самое сложное — вовремя остановиться

Когда я начал делать Micra, самым трудным оказалось не придумать, что добавить, а понять, что не нужно добавлять. Хотелось сделать "по-взрослому": добавить роутер, глубокую реактивность, систему компонентов, свой язык в директивах. Каждый раз, когда возникала такая мысль, я возвращался к изначальной цели — сделать маленькую библиотеку, которую можно просто подключить к существующей серверной разметке.

Ограничение в ~7 КБ оказалось очень полезным дисциплинирующим фактором. Пока ты в него вписываешься, ты физически не можешь превратить инструмент в очередной фреймворк.
Поэтому в Micra сознательно нет:

  • Клиентского роутинга
  • Глубокой реактивности с вложенными объектами
  • Своей системы компонентов
  • Сложного DSL внутри атрибутов

Всё это можно добавить позже (или не добавлять вообще). Главное — не раздувать библиотеку ради "полноты".

Для кого Micra

Micra — это не замена React, Vue или даже Alpine.js. Это инструмент для тех случаев, когда тебе нужна реактивность, но ты не хочешь тащить за собой тяжёлый инструментарий.
Она хорошо подходит для:

  • Админ-панелей и внутренних инструментов
  • Небольших SaaS
  • Сайтов, где основная разметка генерируется на сервере (Rails, Laravel, Django, WordPress и т.д.)
  • Ситуаций, когда хочется быстро добавить интерактивность без отдельного фронтенд-приложения

Если проект требует сложного клиентского состояния, клиентского роутинга и тяжёлой логики — лучше взять полноценный фреймворк. Micra для этого не предназначена.

Я не претендую на то, что придумал что-то революционное. Micra выросла из набора практик, которые я использовал сам, и просто оформилась в отдельную библиотеку. Если тебе удобнее работать с htmx, Stimulus, Alpine или чем-то другим — используй то, что лучше ложится на твои задачи.

Micra лежит на micrajs.dev, исходники под MIT.