Субъективная скорость зачастую важна не меньше, чем реальная производительность сервера. На типичной странице Drupal несколько фрагментов — ссылки аккаунта, меню, панели инструментов, персонализированные виджеты — зависят от пользователя или сессии, тогда как остальная вёрстка может быть закэширована и отдана сразу. Плейсхолдеры и BigPipe — способ Drupal разделить эти задачи: отложить дорогие участки, сначала отправить каркас и заполнить пробелы, когда они будут готовы.
Прежде чем разбирать конфигурационные файлы и render arrays, полезно зафиксировать три термина. В разговоре их часто путают, но в Drupal они описывают разные уровни одного и того же конвейера.
Модель, которая снимает большинство путаницы, последовательная, а не синонимичная:
BigPipe — это не сам механизм плейсхолдеров. Placeholdering относится к Render API; BigPipe — слой прогрессивной доставки, который может работать поверх него.
Каждый контроллер, блок, entity view builder и field formatter в итоге формирует render arrays. По ходу рендерер проверяет, можно ли отложить поддерево, нужно ли превратить его в плейсхолдер и разрешено ли BigPipe передавать результат потоково. Диаграмма ниже показывает эти точки принятия решений.
Drupal обычно требует #lazy_builder в поддереве render array, прежде чем placeholdering станет возможным. Когда callback уже есть, создание плейсхолдера можно запросить явно, получить через block plugin или запустить автоматически при плохой кэшируемости.
Block plugins могут подключиться к пути плейсхолдеров через отдельный метод в BlockPluginInterface. Значение по умолчанию в BlockPluginTrait — FALSE; отдельные блоки переопределяют его, когда отложенный рендеринг оправдан.
public function createPlaceholder(): bool {
return TRUE;
}Этот API относится только к block plugins — не к сущностям, полям или нодам в целом. В ядре Drupal SystemMenuBlock возвращает TRUE, поэтому блоки навигации изначально совместимы с плейсхолдерами. Их вывод часто зависит от активного следа меню и текущего маршрута — контекстов кэша, которые плохо укладываются в одну общую запись кэша страницы.
Любой код, возвращающий render array, может отложить поддерево с помощью #lazy_builder и явно запросить преобразование в плейсхолдер:
$build['dynamic_part'] = [
'#lazy_builder' => [static::class . '::lazyPart', [$id]],
'#create_placeholder' => TRUE,
];Это универсальный паттерн, работающий вне Block API. Типичные точки интеграции: массивы build() блоков, entity view builders, field formatters, contextual link builders и пользовательские контроллеры.
Установка #create_placeholder в FALSE явно запрещает placeholdering, даже если lazy builder присутствует. Это полезно, когда нужна семантика отложенного рендеринга без пути доставки через плейсхолдеры.
Даже без #create_placeholder => TRUE Drupal может автоматически превращать поддеревья с lazy builder в плейсхолдеры, когда метаданные кэшируемости совпадают с настроенными порогами. Значения по умолчанию находятся в sites/default/default.services.yml в секции renderer.config:
renderer.config:
auto_placeholder_conditions:
max-age: 0
contexts: ['session', 'user']
tags: []На практике auto-placeholdering срабатывает, когда у элемента с lazy builder max-age не выше заданного лимита (по умолчанию 0), когда его контексты кэша пересекаются с настроенным списком (session и user по умолчанию) или когда его cache tags совпадают с настроенными тегами (по умолчанию пусто). Отдельные условия можно настроить или отключить: установите max-age в -1 или contexts в [].
Auto-placeholdering не означает, что вся страница проходит через BigPipe. Он затрагивает только отдельные поддеревья, которые уже подходят для placeholdering и несут метаданные кэшируемости, соответствующие этим правилам.
После появления плейсхолдеров отдельный набор условий определяет, будет ли BigPipe передавать их замены потоково или Drupal разрешит их в стандартном потоке с одним ответом. Placeholdering и BigPipe связаны, но это независимые решения.
Согласно BigPipeStrategy в ядре Drupal, BigPipe применяется, когда выполняются все следующие условия:
GET (некэшируемые методы вроде POST исключаются, чтобы формы внутри плейсхолдеров обрабатывались сразу)._no_big_pipe.Когда BigPipe активируется, он использует одну из двух подстратегий. При включённом JavaScript замены передаются в конце страницы и подставляются в DOM — как правило, лучший вариант по воспринимаемой скорости. При наличии cookie big_pipe_nojs или для плейсхолдеров на уровне атрибутов, которые нельзя эффективно найти через querySelector, замены передаются на месте через несколько flush-операций. Оба подхода могут сосуществовать на одной странице.
Echo Flow помогает канадским компаниям с Drupal-разработкой корпоративного уровня.
Распространённый паттерн на контентных сайтах Drupal показывает, как эти элементы складываются в продакшене. Представьте сайт, где модуль big_pipe включён в профиле установки — он входит в ядро Drupal и по умолчанию активен в профиле Standard.
Тема выводит основную навигацию в шапке страницы, часто рендеря блок меню, размещённый в регионе header в page.html.twig. Поскольку SystemMenuBlock подключается к placeholdering, а его контексты кэша зависят от активного следа, авторизованные посетители могут получить быстрый каркас страницы, пока разметка меню ещё строится.
Frontend-коду иногда нужно учитывать эту задержку. Компонент темы в шапке может слушать Drupal behaviors или отслеживать обновления DOM после того, как BigPipe внедрит финальный HTML меню — например, чтобы инициализировать мобильный переключатель, пересчитать sticky-offset или привязать навигацию с клавиатуры, когда ссылки уже на месте. Такой «защитный» JavaScript — практический признак того, что работает рендеринг через плейсхолдеры, даже если для проекта не писали собственный lazy builder.
Для этого паттерна не нужен кастомный lazy builder. Обработка блоков и меню в ядре уже участвует в конвейере плейсхолдеров, когда кэшируемость это оправдывает.
Объявление lazy builder делает отложенный рендеринг возможным, но само по себе не принуждает к созданию плейсхолдера. Auto-placeholdering всё равно может сработать, если метаданные кэшируемости совпадают с настроенными условиями.
$build['links'] = [
'#lazy_builder' => [
static::class . '::renderLinks',
[$entity->id(), $view_mode],
],
];Самый прямой универсальный паттерн, когда вы знаете, что поддерево должно заменяться асинхронно.
$build['links'] = [
'#lazy_builder' => [
static::class . '::renderLinks',
[$entity->id(), $view_mode],
],
'#create_placeholder' => TRUE,
];В block plugins переопределение createPlaceholder() указывает block view builder Drupal направить блок по пути плейсхолдеров.
public function createPlaceholder(): bool {
return TRUE;
}Сам callback возвращает render array, как и любой другой builder. Метаданные кэша этого массива определяют, как сохраняется итоговый вывод и применяется ли auto-placeholdering на предыдущих этапах.
public static function lazyPart($id): array {
return [
'#markup' => 'Rendered later: ' . $id,
'#cache' => [
'contexts' => ['user'],
],
];
}Поскольку вывод зависит от пользователя, это сильный кандидат для auto-placeholdering при условиях renderer.config по умолчанию.
BigPipe окупается, когда у страницы есть содержательный каркас, который держится сам по себе, пока небольшие динамические фрагменты приходят чуть позже. Цель — более быстрый first paint и отзывчивость, а не перенос каждой дорогой операции за плейсхолдер.
Хорошие кандидаты:
Слабые кандидаты:
На тяжёлых страницах поиска BigPipe может помочь с периферийными динамическими фрагментами, но редко становится первым рычагом для медленного списка результатов. Начните с стоимости запросов, настройки Views, тюнинга поискового бэкенда и накладных расходов рендеринга строк. Drupal 11.3 также принёс более широкие оптимизации render cache и плейсхолдеров, снижающие нагрузку на многих страницах — имеет смысл обновиться, прежде чем искать кастомные обходные пути через BigPipe.
#lazy_builder — это поддерево можно построить позже через указанный callback.#create_placeholder — превратить поддерево в плейсхолдер (установите FALSE, чтобы отказаться).createPlaceholder() — вспомогательный метод block plugin; по умолчанию FALSE в BlockPluginTrait.renderer.config; срабатывает по max-age, контекстам кэша и cache tags.Placeholdering — механизм на этапе рендеринга, который позволяет Drupal откладывать работу, не блокируя всю страницу. BigPipe — стратегия доставки, которая может потоково передавать отложенные фрагменты после того, как каркас дошёл до браузера. Понимание того, где принимается каждое решение — lazy builders, явное или автоматическое создание плейсхолдеров и условия BigPipe — сильно упрощает отладку медленных страниц для авторизованных пользователей, проектирование блоков с разумными метаданными кэша и выбор фрагментов, которые стоит откладывать.
Поддерживаете ли вы кастомный блок, настраиваете шапку темы или профилируете сложную View — базовая формулировка остаётся верной: placeholdering определяет, что откладывается; BigPipe определяет, как это приходит.