Как поддерживать огромные меню в Drupal
Однажды я открыл меню Drupal с несколькими тысячами ссылок и наблюдал, как браузер сдался раньше меня. Страница, технически, загрузилась. Но затем каждый клик ощущался так, будто я просил старый принтер объяснить свои чувства.
Начните с BigMenu и Menu Select
Если на сайте Drupal есть большое редакционное меню, первая проблема обычно не в архитектуре. Она в экране редактора. Страница администрирования меню в ядре Drupal может стать мучительной, когда меню разрастается до тысяч ссылок. BigMenu решает это, меняя способ, которым редакторы просматривают меню и управляют им: вместо того чтобы выводить на страницу всё дерево целиком, он позволяет открывать поддеревья через AJAX тогда, когда они нужны редактору. https://www.drupal.org/project/bigmenu
Это звучит как мелочь, пока вы не поработаете со стандартным интерфейсом меню на большом сайте. Свёрнутое дерево всё равно причиняет боль, если Drupal пришлось построить его полностью до того, как страница стала пригодной к использованию. Ценность BigMenu в том, что он избегает этой первоначальной массовой загрузки. Редактор видит ту часть дерева, которую запросил, а не весь лес. https://www.drupal.org/project/bigmenu
Menu Select решает другую раздражающую проблему. В формах материалов редакторам часто нужно выбрать родительский пункт меню. При большом меню обычный выпадающий список выглядит абсурдно. Никто не хочет прокручивать тысячи элементов только для того, чтобы поместить одну страницу под нужного родителя. Menu Select заменяет этот опыт более удобной иерархией и может добавить автодополнение, чтобы редактор мог искать родительскую ссылку, а не вручную охотиться за ней по всему меню. https://www.drupal.org/project/menu_select
Мне нравится такое разделение. BigMenu помогает, когда вы управляете самим меню. Menu Select помогает, когда вы привязываете контент к меню. Их легко спутать, потому что оба касаются UX меню, но они исправляют разные моменты в редакционном рабочем процессе.
Menu Select Ajax: загружайте выбор тогда, когда он нужен редактору
Menu Select с автодополнением уже является большим шагом вперёд. Но на очень крупных сайтах даже более удобный виджет всё ещё может быть слишком тяжёлым, если форма пытается подготовить слишком много данных меню до того, как редактор вообще что-то сделал. Именно здесь имеет смысл AJAX-паттерн выбора меню.
Идея проста: форма не должна строить полный селектор родителя для массивного меню при первоначальной загрузке. Она должна подождать. Когда редактор выбирает меню, вводит поисковый запрос или открывает ветку, Drupal может выполнить небольшой AJAX-запрос и вернуть только совпадающую часть меню. Form API Drupal поддерживает этот паттерн через элементы формы с AJAX, где действие пользователя запускает перестроение на стороне сервера, а заменяется только выбранная часть формы. https://www.drupal.org/docs/develop/drupal-apis/javascript-api/ajax-forms
На практике AJAX-выбор меню обычно имеет два слоя. Первый слой — видимый селектор: поле поиска, выбор родителя или небольшая раскрываемая ветка. Второй слой — сохраняемое значение: фактический ID плагина ссылки меню или ссылка на родителя, которая нужна Drupal при сохранении формы.
Это различие важно. Редакторы должны работать с метками, путями и знакомыми заголовками страниц. Drupal должен хранить стабильные машинные значения. Когда эти две задачи смешиваются, виджеты больших меню становятся хрупкими. Появляются дублирующиеся метки, неясные варианты родителей и медленные перестроения формы.
Хороший поток AJAX-выбора меню ощущается почти скучным. Редактор начинает вводить часть заголовка. Drupal возвращает короткий список возможных родительских ссылок, желательно с достаточным контекстом, чтобы различать одинаковые заголовки. Редактор выбирает одну. Форма сохраняет выбранную ссылку меню за кулисами. Никакого гигантского списка выбора. Никакого рендера всего дерева. Никакого расплавления браузера.
Тот же паттерн работает и для раскрываемых веток. Сначала покажите верхний уровень. Когда редактор открывает родителя, загрузите дочерние элементы этого родителя. Если он открывает ещё один дочерний элемент, загрузите следующий уровень. Именно так должен вести себя интерфейс, когда набор данных большой: небольшой запрос, небольшой ответ, понятное следующее действие.
При 10 000 пунктах меню перестаньте загружать вперёд
Когда меню достигает примерно 10 000 пунктов, я перестаю думать о нём как об обычном меню Drupal. Технически это всё ещё меню. Операционно оно больше похоже на индекс контента в форме дерева.
Распространённая ошибка — начинать с корня, загружать всё дерево, раскрывать активный путь, а затем выбрасывать большую часть результата. Это работает на маленьких меню. На огромном меню это движение в неправильную сторону.
Лучший подход, который я использовал, — обратная загрузка. Начните с активной ссылки меню для текущей страницы. От неё загрузите только её родителей. Это даёт активный путь без необходимости просить Drupal строить все несвязанные ветки. API меню Drupal поддерживают такое направление движения: менеджер ссылок меню может находить ссылки по маршруту, а также предоставляет ID родителей для плагина ссылки меню. https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Menu%21MenuActiveTrail.php/11.x https://api.drupal.org/api/drupal/core%21lib%21drupal%21core%21menu%21menulinkmanagerinterface.php/function/menulinkmanagerinterface%3A%3Agetparentids/9
Это полностью меняет профиль затрат. В огромном меню может быть 10 000 пунктов, но активный путь для страницы обычно короткий. Может быть пять уровней. Может быть семь. Даже в глубоком каталоге редко бывают десятки предков для одного элемента. Поэтому вместо загрузки 10 000 ссылок, чтобы обнаружить один путь, вы загружаете активный элемент и идёте вверх.
После этого можно решить, сколько окружающей навигации странице действительно нужно. Иногда достаточно родительского пути. Иногда нужны также дочерние элементы активного пункта. Иногда нужны соседние элементы на одном уровне для меню раздела. Отлично. Загружайте эти срезы осознанно. Не позволяйте фразе «нам нужна навигация» незаметно превратиться в «загружать всё дерево при каждом запросе».
Система деревьев меню Drupal уже мыслит категориями параметров дерева, активных путей и трансформаций. Обычный подход к загрузке дерева может раскрывать ссылки вдоль текущего активного пути, что полезно для нормальных меню. https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Menu%21MenuLinkTreeInterface.php/interface/MenuLinkTreeInterface/8.2.x Но для очень большого меню я предпочитаю быть строже. Сначала найдите активную ссылку. Затем загрузите её родителей. Затем загрузите только ту ветку, которая нужна для текущей страницы.
Настоящее правило сопровождения: никогда не заставляйте редакторов платить за всё меню
Огромные меню Drupal — это не только проблема рендеринга. Это редакционная проблема, проблема построения форм, проблема кэша, а иногда и проблема информационной архитектуры, которую кто-то откладывал три года.
BigMenu помогает редакторам работать с большими деревьями, не открывая всё сразу. https://www.drupal.org/project/bigmenu Menu Select делает выбор родителя терпимым, особенно с автодополнением. https://www.drupal.org/project/menu_select AJAX-выбор не даёт формам подготавливать тысячи вариантов до того, как редактор сделал первый осмысленный клик. https://www.drupal.org/docs/develop/drupal-apis/javascript-api/ajax-forms
Для фронтенд-навигации обратная загрузка — это та часть, которую я бы защищал наиболее настойчиво. Начните с активной ссылки меню. Загружайте только родителей. Добавляйте дочерние или соседние элементы только тогда, когда они действительно нужны дизайну. Одна эта привычка не даёт меню из 10 000 пунктов превращать каждый запрос в наказание.
Браузер никогда не должен тащить на себе всё меню только потому, что одной странице нужно знать, где она находится.
Ищете лучшую компанию по разработке на Drupal на рынке? Вы только что её нашли.
Мы — крупнейшее digital-агентство, сфокусированное на Drupal, созданное для быстрой, безопасной и масштабируемой разработки платформ без компромиссов. От новых проектов и редизайнов до миграций и долгосрочной поддержки — наши эксперты Drupal поставляют результаты корпоративного уровня с вниманием бутикового агентства.
Забронируйте звонок сегодня, и давайте превратим вашу дорожную карту Drupal в высокопроизводительную реальность.
Ivan Abramenko, ведущий архитектор Drupal
ivan.abramenko@drupalbook.org
projects@drupalbook.org