Stimulus — JavaScript-фреймворк, ориентированный на усиление существующей HTML-разметки без её радикальной перестройки. Эта особенность делает его особенно подходящим для работы с легаси-кодом, где уже присутствует серверный рендеринг, разрозненные скрипты, inline-обработчики и непоследовательная архитектура.
В контексте рефакторинга ключевая ценность Stimulus заключается в инкрементальности: код можно улучшать по частям, не переписывая приложение целиком и не нарушая текущую функциональность.
Легаси-код в браузере обычно характеризуется следующими признаками:
onclick,
onchange);document.querySelector и
addEventListener в разных файлах;Пример характерного фрагмента:
<button oncl ick="toggleMenu()">Меню</button>
<script>
function toggleMenu() {
var menu = document.getElementById('menu');
menu.classList.toggle('open');
}
</script>
Такой код работает, но масштабируется плохо и быстро теряет управляемость.
Stimulus строится вокруг идеи, что HTML уже содержит всю необходимую информацию о поведении интерфейса. JavaScript не управляет DOM напрямую, а подключается к нему декларативно.
Основные концепции:
data-controller — привязка логики к DOM-элементу;data-action — декларативное описание событий;data-target — именованные ссылки на элементы внутри
контроллера;values и classes — конфигурация и
состояние через атрибуты.Это позволяет переносить поведение из разрозненных скриптов в структурированные контроллеры, не меняя семантику разметки.
Начальный этап — перенос логики из глобальной области видимости в Stimulus-контроллер без изменения внешнего поведения.
Исходное состояние:
<button id="menuButton">Меню</button>
<div id="menu"></div>
<script>
document.getElementById('menuButton').addEventListener('click', function () {
document.getElementById('menu').classList.toggle('open');
});
</script>
Рефакторинг с использованием Stimulus:
<div data-controller="menu">
<button data-action="click->menu#toggle">Меню</button>
<div data-menu-target="panel"></div>
</div>
import { Controller } from "@hotwired/stimulus";
export default class extends Controller {
static targets = ["panel"];
toggle() {
this.panelTarget.classList.toggle("open");
}
}
Поведение осталось тем же, но:
В легаси-проектах часто встречаются файлы на сотни строк, обслуживающие сразу несколько элементов страницы. Stimulus позволяет разделять ответственность без полной переработки.
Стратегия:
Пример: один файл управляет модальными окнами, табами и тултипами.
Каждый из этих элементов может быть вынесен в собственный контроллер
(modal, tabs, tooltip) без
влияния на остальной код.
Stimulus не требует перестройки HTML. Атрибуты data-*
добавляются поверх существующей структуры.
Пример легаси-шаблона:
<ul class="tabs">
<li class="active">Профиль</li>
<li>Настройки</li>
</ul>
Минимальный рефакторинг:
<ul class="tabs" data-controller="tabs">
<li data-action="click->tabs#select" data-tabs-target="tab" class="active">Профиль</li>
<li data-action="click->tabs#select" data-tabs-target="tab">Настройки</li>
</ul>
Контроллер берет на себя управление состоянием, не меняя CSS и визуальное представление.
Во многих легаси-проектах Stimulus используется как мост при уходе от jQuery.
Типичный jQuery-код:
$('.dropdown-toggle').on('click', function () {
$(this).next('.dropdown-menu').toggle();
});
Эквивалент на Stimulus:
<div data-controller="dropdown">
<button data-action="click->dropdown#toggle">...</button>
<div data-dropdown-target="menu"></div>
</div>
toggle() {
this.menuTarget.classList.toggle("hidden");
}
Переход возможен постепенно: jQuery продолжает работать в других частях приложения, а новый код сразу пишется на Stimulus.
Легаси-код часто хранит состояние в DOM, глобальных переменных или
замыканиях. Stimulus предоставляет механизм values, который
делает состояние явным и типизированным.
<div
data-controller="counter"
data-counter-count-value="0">
</div>
static values = { count: Number };
increment() {
this.countValue++;
}
Состояние:
Stimulus автоматически управляет жизненным циклом контроллеров:
connect — элемент появился в DOM;disconnect — элемент удалён;initialize — создание экземпляра.Это особенно важно при работе с легаси-кодом, где DOM может динамически меняться (AJAX, Turbo, server-side рендеринг).
Вместо ручного пересоздания обработчиков:
connect() {
this.startObserving();
}
disconnect() {
this.stopObserving();
}
Код становится устойчивым к перерисовкам и частичным обновлениям страницы.
Stimulus органично работает в приложениях без SPA-архитектуры. Это критично для легаси-систем, построенных вокруг серверных шаблонов.
Особенности:
Это позволяет улучшать UX без изменения архитектурных основ проекта.
Использование Stimulus переводит рефакторинг из разряда «переписать всё» в режим постоянного улучшения:
В результате легаси-проект перестаёт быть «замороженным» и снова становится пригодным для развития без резких и рискованных изменений.