SSR-блоки
Блок становится SSR-блоком автоматически: достаточно объявить в схеме
bindingSlots. Отдельного флага нет.
Разница принципиальная. Обычный блок PageCraft рендерит сам и отдаёт витрине
готовый HTML. SSR-блок отдаётся шаблоном: витрина добывает данные выбранного
источника, подставляет их в data.<слот> и рендерит шаблон у себя — уже с реальным
содержимым магазина и в момент запроса страницы посетителем.
Что уезжает при публикации
Заголовок раздела «Что уезжает при публикации»Шаблон блока заворачивается в <template> внутри контейнера-якоря, по которому
рантайм витрины его находит:
<div data-block-wrapper-id="4218" style="display: contents"> <template data-block-id="4218"> <h2>{{ props.title }}</h2> <ul>{% for product in data.products.items %}…{% endfor %}</ul> </template></div>Рядом с HTML страницы уходит контекст — по записи на каждый SSR-блок:
{ "version": 1, "blocks": { "4218": { "type": "Карточки товаров", "version": "2.1", "props": { "title": "Хиты продаж" }, "binding": { "products": { "source": "catalog.products", "params": { "limit": 8 } } } } }}Ключ — идентификатор вхождения блока на странице, он же data-block-id. binding
здесь уже разрешён: пустые слоты дозаполнены дефолтами схемы, а слоты, чей
контекстный источник
на этом виде документа не работает, из binding исключены — шаблон получит по ним
null. Маркера контекстности в публикуемом теле нет: формат остаётся
{ source, params }, а данные из окружения источник добывает на витрине сам.
CSS и JS SSR-блока собираются и публикуются обычным порядком, вместе со стилями остальных блоков страницы, — на них SSR никак не влияет.
SSR-блок внутри блока-контейнера
Заголовок раздела «SSR-блок внутри блока-контейнера»Если SSR-блок лежит в слоте контейнера,
он уезжает <template>-ом внутри <template> родителя, а в context попадает
наравне с блоками верхнего уровня: структура context плоская, по ней нельзя понять,
что один блок внутри другого. Вложенность выражена только вёрсткой, и разбирает её
рантайм витрины — изнутри наружу.
Два следствия для автора шаблона:
- вложенный SSR-блок получает данные по своей записи в
context, независимо от родителя. Контейнер не «раздаёт» ему элементы своей коллекции: такой механизм — отдельная возможность, и её пока нет; - контейнер сам может быть SSR-блоком. Тогда PageCraft подставляет в его шаблон
только
{{ slots.<имя> }}— собранный HTML детей, — а всё остальное уезжает нерендеренным, как у обычного SSR-блока.
Обновление по событиям витрины
Заголовок раздела «Обновление по событиям витрины»Блок, зависящий от корзины, должен переставать врать сразу после её изменения.
Для этого в схеме объявляется client.refreshOn:
{ "bindingSlots": { "cart": { "resultType": "cart_summary", "allowedSources": ["cart.current"] } }, "client": { "refreshOn": ["cart.change"] }}При публикации список превращается в атрибут контейнера
(data-refresh-on="cart.change"), и рантайм витрины перерисовывает блок на сервере,
подменяя его в DOM. Сейчас поддерживается одно событие — cart.change
(состав или количество товаров в корзине изменились).
Указывайте только реально нужные события: каждая подписка — дополнительные
SSR-запросы к витрине. Для блока без bindingSlots секция client смысла не имеет.
Чем это оборачивается для автора шаблона
Заголовок раздела «Чем это оборачивается для автора шаблона»Дефолты полей в SSR-контекст не подставляются. У обычного блока пустые
placeholder_values при рендере заменяются дефолтами схемы; в контекст SSR-блока
props уезжают ровно такими, какими лежат в базе. Заполняйте
placeholder_values явно.
Переменные сайта @имя в шаблоне SSR-блока не раскрываются. Подстановка идёт
по отрендеренному HTML, а шаблон SSR-блока на этом этапе ещё не отрендерен и уезжает
как есть. Всё, что зависит от переменных сайта, держите в обычных блоках или в макете.
Ошибки шаблона всплывут только на витрине. Локальный рендер SSR-блока не выполняется вовсе, а предпросмотр в редакторе идёт на заглушке типа результата — на одном аккуратном наборе данных. Пишите шаблон устойчивым: проверяйте пустой список, отсутствующие поля и нули.
{% if data.products.items.size > 0 %} {% for product in data.products.items %} <li>{{ product.name }} — {{ product.variation.price.formatted | default: '—' }}</li> {% endfor %}{% else %} <p>Товары не найдены</p>{% endif %}Клиентские запросы не нужны. Смысл SSR-блока в том, что данные приходят вместе с разметкой: поисковик видит товары, а посетитель не ждёт дозагрузки.
Ограничение публикации
Заголовок раздела «Ограничение публикации»SSR-режим работает только там, где на стороне сайта есть рантайм, умеющий
разворачивать <template data-block-id>. Сегодня это публикация в 4CMS. Публикация
статикой по FTP рендерит все блоки на стороне PageCraft, поэтому блоку с
bindingSlots там взяться данным неоткуда — для статических сайтов используйте
обычные блоки.
Источники: backend/src/Publishing/BlockAssembler.php
(renderBlocksWithSsr, wrapBindingBlock),
backend/src/Publishing/Provider/FourCmsProvider.php (buildSsrContext),
backend/src/Publishing/Provider/FtpProvider.php,
backend/src/Publishing/BlockRenderer.php,
backend/public/block-schema.json (client.refreshOn),
backend/src/Service/Block/BlockBindingsResolver.php.