Различия сервера и браузера
Один и тот же шаблон в PageCraft выполняется дважды разными движками:
| Предпросмотр в редакторе | Публикация страницы | |
|---|---|---|
| Движок | LiquidJS (JavaScript) | keepsuit/liquid (PHP) |
| Где считается | в вашем браузере | на сервере PageCraft |
| Когда | на каждое нажатие клавиши | при публикации |
Так сделано ради отзывчивости редактора: ходить на сервер за каждым символом нельзя, а отдавать витрине результат из браузера — тем более. Цена — расхождения. Все они проявляются одинаково неприятно: в редакторе выглядело иначе, чем на сайте, без единой ошибки.
Ниже — полный список расхождений, которые ловятся на практике. Держитесь общего подмножества, и предпросмотр будет честным.
1. Фильтры, которых нет на сервере
Заголовок раздела «1. Фильтры, которых нет на сервере»LiquidJS богаче: у него есть фильтры, которых в серверном движке не существует. Незнакомый фильтр сервер не считает ошибкой — он возвращает значение без преобразования.
{{ props.title | slugify }}| Результат | |
|---|---|
| Предпросмотр | hello-world |
| Опубликованная страница | Hello World |
Фильтры, работающие только в предпросмотре:
array_to_sentence_string · base64_decode · base64_encode · cgi_escape ·
date_to_long_string · date_to_rfc822 · date_to_string · date_to_xmlschema ·
find_exp · find_index_exp · group_by · group_by_exp · has_exp · inspect ·
json · jsonify · normalize_whitespace · number_of_words · pop · push ·
raw · reject_exp · sample · shift · slugify · to_integer · unshift ·
uri_escape · where_exp · xml_escape
Обратного списка нет: фильтров, которые есть на сервере и отсутствуют в браузере, не существует. Безопасный набор из 55 фильтров — в Liquid: основы.
2. Теги
Заголовок раздела «2. Теги»| Тег | Предпросмотр | Публикация |
|---|---|---|
assign capture if unless case for tablerow cycle increment decrement raw comment echo liquid |
работает | работает |
{% ifchanged %} |
ошибка | работает |
{% doc %} |
ошибка | работает |
{% include %} {% render %} {% layout %} {% block %} |
ошибка | ошибка |
Практический вывод: ifchanged и doc в шаблоне блока не используйте — предпросмотр
на них ломается целиком. Подключение внешних шаблонов не работает нигде.
3. Операторы || и &&
Заголовок раздела «3. Операторы || и &&»В шаблоне блока это синтаксическая ошибка везде — и в браузере, и на сервере.
В шаблоне макета сервер перед рендерингом молча переписывает || → or,
&& → and, а {{ a || b }} → {{ a | default: b }}. В предпросмотре макета такой
замены нет.
Где написан || |
Предпросмотр | Публикация |
|---|---|---|
| Шаблон блока | ошибка | ошибка |
| Шаблон макета | ошибка | работает |
Пишите or, and и default: — они ведут себя одинаково во всех четырёх клетках.
4. Ключевое слово blank
Заголовок раздела «4. Ключевое слово blank»{% if props.title == blank %}пусто{% endif %}В браузере условие истинно для пустой строки, на сервере blank не существует
и условие всегда ложно. Сравнивайте с пустой строкой: props.title == ''.
5. Markdown
Заголовок раздела «5. Markdown»Markdown-блок конвертируется двумя разными библиотеками, и синтаксис GitHub-стиля поддерживает только браузерная. Полная таблица и что с этим делать — Markdown в блоках.
6. Пробелы и переносы в выводе
Заголовок раздела «6. Пробелы и переносы в выводе»Мелочь, о которую спотыкаются CSS-селекторы вроде td + td: {% tablerow %}
на сервере ставит переносы строк между ячейками, в браузере — нет. Если вёрстка
зависит от отсутствия пробельных узлов, не полагайтесь на предпросмотр.
7. Блоки с живыми данными вообще не рендерятся на сервере
Заголовок раздела «7. Блоки с живыми данными вообще не рендерятся на сервере»Блок, объявивший bindingSlots, PageCraft при публикации не выполняет: на витрину
уезжает исходный шаблон, а данные подставляет магазин своим движком Liquid — уже
третьим. В редакторе слоты заполнены заглушкой типа результата.
Значит, у такого блока предпросмотр не проверяет ни фильтры, ни теги на реальном движке витрины, а данные в нём всегда «идеальные»: без пустых списков, длинных названий и отсутствующих картинок. Проверяйте шаблон на краевых случаях руками — пустой список, одна позиция, очень длинная строка.
8. Блоки типа html — наследие
Заголовок раздела «8. Блоки типа html — наследие»Старый тип блока html Liquid не использует вовсе: в нём {{ ключ }} заменяется
простой текстовой подстановкой, и правила этой страницы к нему не относятся.
Новые блоки делайте типа «schema» или «markdown».
Что делать, чтобы не попасть
Заголовок раздела «Что делать, чтобы не попасть»- Ограничьтесь общим набором фильтров и тегов.
- Никаких
||,&&,blank— толькоor,and,default:,== ''. - После первой публикации посмотрите на страницу на витрине, а не только в предпросмотр.
- Блока не видно на опубликованной странице — ищите в её исходном коде
<!-- Liquid render error: … -->: ошибка шаблона блока не отменяет публикацию и никак не сигнализируется. - Ошибка в шаблоне макета, наоборот, останавливает публикацию с текстом ошибки — тут молчания не будет.
Источники: backend/src/Publishing/BlockRenderer.php,
backend/src/Publishing/LayoutRenderer.php (normalizeOperators),
backend/src/Publishing/BlockAssembler.php, front/src/lib/liquid.ts,
front/src/lib/placeholder.ts, front/src/components/PageEditor/PageEditor.tsx,
keepsuit/liquid 0.9 против liquidjs 10.25 — списки фильтров и тегов сверены
прогоном обоих движков.