Prefetch в контексте Stimulus — это управляемая предзагрузка данных, шаблонов и вспомогательных ресурсов на стороне клиента до момента фактического взаимодействия пользователя. Основная идея — сократить задержки интерфейса за счёт выполнения потенциально дорогих операций заранее, но без нарушения принципов прогрессивного улучшения и без избыточной нагрузки на сеть.
Stimulus не предоставляет отдельного встроенного API под названием
prefetch, однако архитектура фреймворка идеально подходит
для реализации предзагрузки через контроллеры, lifecycle-хуки и
интеграцию с браузерными механизмами (link rel="prefetch",
fetch, IntersectionObserver).
Stimulus-контроллер проходит несколько фаз жизни, каждая из которых может быть использована для предзагрузки ресурсов:
initialize() — инициализация, логика без доступа к
DOMconnect() — контроллер подключён к DOMdisconnect() — удаление из DOMДля prefetch чаще всего используется connect(), так как
в этот момент доступна информация о состоянии страницы и атрибутах
элемента.
import { Controller } from "@hotwired/stimulus"
export default class extends Controller {
connect() {
this.prefetchData()
}
async prefetchData() {
await fetch("/api/products")
}
}
Такой подход гарантирует, что данные начнут загружаться сразу после появления релевантного DOM-узла, но до пользовательского действия.
Prefetch не должен быть безусловным. Стимулюс позволяет гибко управлять логикой через values и data-атрибуты.
<div
data-controller="products"
data-products-prefetch-value="true">
</div>
export default class extends Controller {
static values = { prefetch: Boolean }
connect() {
if (this.prefetchValue) {
this.loadProducts()
}
}
}
Такой механизм делает prefetch декларативным и легко управляемым на уровне шаблонов.
Одной из наиболее эффективных стратегий является prefetch по косвенному намерению: наведение курсора, фокус, начало скролла.
Stimulus отлично подходит для такой модели, поскольку события объявляются декларативно.
<a
href="/profile"
data-controller="prefetch"
data-action="mouseenter->prefetch#load">
Профиль
</a>
export default class extends Controller {
load() {
fetch(this.element.href, { credentials: "same-origin" })
}
}
Ресурс будет загружен в момент, когда вероятность перехода высока, но до фактического клика.
Для тяжёлых ресурсов (модальные окна, формы, дополнительные секции) эффективна предзагрузка при приближении элемента к области видимости.
export default class extends Controller {
connect() {
this.observer = new IntersectionObserver(entries => {
if (entries[0].isIntersecting) {
this.prefetch()
this.observer.disconnect()
}
})
this.observer.observe(this.element)
}
prefetch() {
fetch("/modal/content")
}
}
Stimulus здесь выступает в роли координатора, а браузер — в роли оптимизатора.
<link rel="prefetch"> под управлением StimulusВ некоторых случаях предпочтительнее задействовать нативный prefetch браузера. Stimulus может динамически добавлять соответствующие теги.
export default class extends Controller {
connect() {
const link = document.createElement("link")
link.rel = "prefetch"
link.href = "/assets/chart.js"
document.head.appendChild(link)
}
}
Преимущество — браузер сам определяет приоритет загрузки и не блокирует основной поток.
Prefetch без кэширования быстро теряет смысл. Часто используется простой in-memory кэш внутри контроллера или общего модуля.
let cache = null
export default class extends Controller {
async prefetch() {
if (!cache) {
cache = await fetch("/api/stats").then(r => r.json())
}
}
}
Stimulus не навязывает архитектуру хранения данных, что позволяет комбинировать его с любыми стратегиями кэширования.
Хорошей практикой является вынос предзагрузки в отдельные контроллеры, не смешивая её с UI-логикой.
<div data-controller="prefetch" data-prefetch-url-value="/settings"></div>
export default class extends Controller {
static values = { url: String }
connect() {
fetch(this.urlValue)
}
}
Такой контроллер можно переиспользовать на разных страницах без дублирования кода.
Для сложных интерфейсов важно уметь отменять prefetch при изменении
контекста. Используется AbortController.
export default class extends Controller {
connect() {
this.abortController = new AbortController()
fetch("/api/preview", { signal: this.abortController.signal })
}
disconnect() {
this.abortController.abort()
}
}
Это предотвращает утечки ресурсов при динамическом обновлении DOM.
В экосистеме Hotwire Stimulus часто используется совместно с Turbo. Prefetch может подготавливать данные или состояния перед Turbo-навигацией, не вмешиваясь в сам механизм переходов.
Типичный сценарий — предзагрузка JSON, который затем используется для
мгновенного рендера после turbo:load.
Prefetch не должен:
navigator.connectionStimulus позволяет встроить эти проверки локально и декларативно, не усложняя глобальную архитектуру.
Prefetch в Stimulus — это не отдельная технология, а паттерн. Он реализуется через небольшие, изолированные контроллеры, использующие нативные возможности браузера и минимальное количество JavaScript. Такой подход сохраняет философию фреймворка: тонкий слой поведения поверх HTML с максимальной предсказуемостью и контролем.