Turbo Drive отвечает за навигацию без полной перезагрузки страницы,
перехватывая переходы по ссылкам и отправку форм. Вместо классического
обновления документа происходит замена содержимого
<body> с сохранением текущего JavaScript-контекста.
Stimulus в этой архитектуре выполняет роль слоя поведения, автоматически
подключая и отключая контроллеры при изменении DOM.
Такое разделение обязанностей позволяет отказаться от ручной инициализации JavaScript при каждой навигации и свести логику интерфейса к декларативному описанию в разметке.
При обычной загрузке страницы Stimulus сканирует DOM, находит
элементы с data-controller и вызывает методы
connect. Turbo Drive при переходах заменяет
<body>, после чего:
disconnect для
контроллеров удалённых элементов;connect для контроллеров новых
элементов.Дополнительной инициализации не требуется, если код контроллеров не опирается на глобальное состояние, связанное с конкретной страницей.
Ключевой момент: JavaScript-контекст не пересоздаётся, но жизненный цикл контроллеров полностью отрабатывается заново.
Turbo Drive генерирует ряд событий, отражающих этапы навигации. Они часто используются для тонкой синхронизации Stimulus-логики с процессом перехода.
Основные события:
turbo:visit — начало перехода.turbo:before-render — перед подменой
<body>.turbo:render — после вставки нового содержимого.turbo:load — завершение навигации и отрисовки.turbo:before-cache — перед сохранением текущей страницы
в кэш.В контексте Stimulus особенно важно событие
turbo:before-cache. Оно возникает перед тем, как Turbo
Drive сохранит текущий DOM в память для возможного возврата назад.
Пример типового применения — очистка временного состояния:
// example_controller.js
import { Controller } from "@hotwired/stimulus"
export default class extends Controller {
connect() {
this.beforeCacheHandler = this.beforeCache.bind(this)
document.addEventListener("turbo:before-cache", this.beforeCacheHandler)
}
disconnect() {
document.removeEventListener("turbo:before-cache", this.beforeCacheHandler)
}
beforeCache() {
this.element.classList.remove("is-open")
}
}
Такой подход предотвращает сохранение в кэше «грязного» DOM-состояния.
Turbo Drive кэширует посещённые страницы. При возврате назад происходит мгновенное восстановление DOM из памяти без повторного HTTP-запроса.
Особенности этого механизма:
connect у контроллеров вызывается заново;turbo:load также срабатывает;Если контроллер управляет состоянием, которое не должно переживать навигацию (модальные окна, временные подсказки, раскрытые панели), это состояние должно быть сброшено до кэширования.
Атрибут data-turbo-permanent указывает Turbo Drive не
удалять элемент при навигации. Такой элемент сохраняется между
страницами и не пересоздаётся.
Последствия для Stimulus:
disconnect и connect при переходах;Это удобно для:
При использовании data-turbo-permanent особенно важно
учитывать, что контроллер фактически становится «долгоживущим» и может
накапливать побочные эффекты, если не реализована корректная очистка
ресурсов.
Turbo Drive перехватывает отправку форм и выполняет её асинхронно. Stimulus-контроллеры, привязанные к формам, продолжают работать без изменений.
Частый паттерн — управление состоянием формы в процессе отправки:
Так как после успешной отправки происходит подмена
<body>, все визуальные эффекты, связанные с формой,
должны либо завершаться до навигации, либо корректно сбрасываться через
turbo:before-cache.
Turbo Frames позволяют обновлять только часть страницы. В этом случае Stimulus получает ещё более локализованный жизненный цикл:
Это позволяет строить интерфейсы, где Stimulus-логика точно следует за границами обновляемых фрагментов. Контроллеры становятся по-настоящему компонентными и не зависят от глобальных событий навигации.
Так как Turbo Drive не перезагружает JavaScript-среду, глобальные переменные и синглтоны сохраняются между страницами. В сочетании со Stimulus это требует аккуратного подхода:
disconnect;Stimulus предполагает, что контроллер является полностью самодостаточной единицей, корректно реагирующей на появление и исчезновение элемента в DOM. Turbo Drive делает это предположение критически важным.
На практике связка выглядит следующим образом:
Такой подход устраняет необходимость в ручной маршрутизации на стороне клиента и в сложных состояниях SPA, сохраняя при этом высокую отзывчивость интерфейса и простоту сопровождения кода.