Современный веб попал в парадоксальную ловушку: чтобы показать пользователю простую кнопку «Купить» или выпадающее меню, браузер сначала скачивает сотни килобайтов JavaScript, долго разбирает их и повторно собирает на клиенте то, что сервер уже отрендерил. Этот процесс называется гидратацией. На мощном ноутбуке задержка в доли секунды незаметна, но на обычном смартфоне экран на пару секунд замирает: интерфейс уже виден, однако нажатия игнорируются, пока процессор занят разбором скриптов. Открытая библиотека CycleWire решает эту проблему радикально, предлагая селективную активацию в компактном ядре весом всего 5,2 КБ.
Почему мобильные интерфейсы замирают при загрузке
В классических фреймворках вроде Next.js страница отдается в виде готового HTML, но затем запускается клиентский рантайм. Движок обходит DOM-дерево, строит виртуальные узлы в памяти и привязывает обработчики ко всем элементам. На смартфонах это увеличивает показатель Total Blocking Time (TBT) — время, когда браузер заблокирован и не реагирует на ввод. В тестах на 4-ядерных мобильных процессорах TBT у традиционных фреймворков доходит до 110–150 мс, тогда как у CycleWire держится на нуле. Библиотека полностью отказывается от начального клиентского бандла: сервер отдает чистый HTML, а браузер подтягивает логику только тогда, когда пользователь начинает взаимодействовать с элементом.
Загрузка по намерению: модуль скачивается до клика
Вместо того чтобы ждать физического нажатия и заставлять человека наблюдать спиннер, CycleWire использует упреждающую загрузку по намерению (intent-aware loading). Как только курсор приближается к кнопке (pointerenter), поле ввода получает фокус (focusin) или блок появляется в зоне видимости (IntersectionObserver), движок добавляет в заголовок страницы тег <link rel="modulepreload">.
Браузер незаметно скачивает крошечный модуль действия заранее по HTTP/2, не тратя время на его исполнение. Когда пользователь нажимает кнопку, код уже находится в памяти и срабатывает без сетевой паузы. Если же на устройстве включен режим экономии трафика Save-Data или скорость сети упала до 2G, спекулятивная предзагрузка отключается автоматически.
Декларативная привязка и защита от дублирования запросов
Интерактивность в CycleWire описывается прямо в серверном HTML через декларативные атрибуты, без привязки к конкретному бэкенду:
<!-- Серверная разметка кнопки с предзагрузкой и защитой от повторных нажатий -->
<div class="product-card" id="item-42">
<h3>Механическая клавиатура</h3>
<button
cw-action="cart#add"
cw-props='{"id": 42, "qty": 1}'
cw-concurrency="drop"
cw-preload="intent"
class="btn-primary"
>
В корзину
</button>
</div>
Атрибут cw-action указывает модуль и экспортируемую функцию, а режим cw-concurrency="drop" игнорирует повторные клики до завершения первого запроса, предотвращая дублирование заказов. Сам обработчик пишется как изолированный асинхронный модуль с поддержкой AbortSignal:
// actions/cart.js — скачивается браузером только по требованию
export async function add({ element, props, signal }) {
element.disabled = true;
element.textContent = 'Сохранение...';
try {
const response = await fetch('/api/cart/items', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(props),
signal, // отмена при уходе со страницы или новом действии
});
if (!response.ok) throw new Error(`Ошибка: ${response.status}`);
const data = await response.json();
element.textContent = 'Добавлено ✓';
window.dispatchEvent(new CustomEvent('cart:updated', { detail: data }));
} catch (error) {
if (signal.aborted) return;
element.textContent = 'Сбой, повторите';
} finally {
element.disabled = false;
}
}
Архитектурный баланс: кому подходит селективный рантайм
CycleWire сочетает подход Qwik с простотой htmx, но не требует специфического компилятора разметки. Движок модульный: для динамического обновления верстки без перезагрузки страницы подключается модуль cyclewire/morph (2,2 КБ), который точечно синхронизирует узлы реального DOM с сохранением фокуса в формах, не создавая тяжелого виртуального дерева.
Граница применимости решения очевидна: CycleWire не предназначен для сложных приложений уровня графических редакторов или тяжелых таблиц, где сотни компонентов ежесекундно пересчитывают общее клиентское состояние. Зато для интернет-магазинов, медиапорталов и классических веб-сервисов на PHP, Python, Ruby или Go это практичный инструмент, позволяющий получить мгновенный отклик интерфейса и максимальные баллы Core Web Vitals без перевода всего проекта на React.
