Шаблон CSSSR: нужно ли разделение блоков на группы?

Доброго времени суток! С вами один из ведущих разработчиков CSSSR — Паша. Не так давно, в феврале 2016, на моём проекте случился долгожданный переход с Grunt на Gulp. Да, я знаю, что это устаревшая технология, но проект стартовал очень давно, а его объём огромен. В итоге мы смогли «переехать», и я хотел бы поделиться нашим опытом сборки в целом и структурой шаблона на проекте в частности.

Предисловие

Вёрстка у нас на проекте очень специфическая — мы верстаем под CMS Liferay. Сама вёрстка состоит из независимых «портлетов» (это термин CMS, означает виджеты, секции и подобное). К тому же любые динамические данные в разметке портлета доставляют кучу проблем бекенду. Все данные мы ещё год назад решили хранить в JavaScript-переменной в формате JSON, и эта традиция сохранилась после перехода на Gulp.

В один прекрасный момент стартовал подпроект, и завертелось: готовились оценки и спецификации, писалось ТЗ, всё кипело, но дизайна ещё не было, — и я понял, что настало время! Мое предложение оптимизации рабочего пространства фронтенда было принято, и я приступил к работе. В качестве основы был выбран шаблон CSSSR, но с модификациями папки app/blocks и разделением всех блоков на группы. Об этом я и буду писать дальше.

Независимые секции страниц

Как я говорил, вёрстка должна состоять из независимых портлетов. Чтобы избежать путаницы, мы создали папку app/portlets и размещали такие блоки там. Именно портлеты подключаются в app/pages. Как вы знаете, в шаблоне CSSSR не используют папки внутри блоков, но у нас же это, наоборот, приветствуется. Чтобы понять, зачем это нужно, разберём портлет «отзывы».

В принципе ясно, что сам портлет будет лежать в корне нашей папки app/portlets/reviews, а сам блок будет состоять из списка отзывов и самого отзыва. С последним как раз и появляются проблемы: в шаблоне CSSSR мы бы разложили их в два блока app/blocks/reviews и app/blocks/reviews-item, но это было бы правильным только в случае, если бы мы использовали reviews-item в других местах, а на практике он будет использоваться только внутри самого reviews. Я решил, что будет правильнее держать эти блоки внутри их родителя, и ему достался путь app/portlets/reviews/item. Важно понимать, что такие блоки используют именование путем наследования класса родителя, чтобы не создавать путаницы .reviews и .reviews-item. Некоторым это покажется «дикостью», но это, на мой взгляд, правильная БЭМ-иерархия.

Шаблоны — наши любимые заготовки

Для сборки страниц мы используем шаблоны app/layouts. Раньше так было и в шаблоне CSSSR, но эту практику оставили и их перенесли в app/blocks. Так как шаблоны не являются блоками, я решил вернуть эту старую добрую традицию. Больше тут нечего рассказывать, идем дальше.

Запчасти или как не мусорить

Также я посмел выделить ещё один тип блоков — запчасти app/partials. Назначение этих блоков очень специфическое — их используют исключительно для шаблонов. Это могут быть шапка сайта, подвал, боковое меню и прочие элементы, подключающиеся в app/layouts. Так мы не захламляем основные папки блоками, которые нигде больше не будут подключаться.

UI-Kit нужно держать в одном месте

Как ни странно, у нас осталась папка app/blocks, хоть и изменилось её назначение. Все блоки, которые являются UI-Kit элементами, собираются в ней. Это могут быть любые блоки, использующиеся в других местах: самые разнообразные кнопки, ссылки, текстовые поля, выпадающие списки, заголовки, знаки рубля, чекбоксы, радиобатоны и тд., — их разнообразие неописуемо, а применяются они везде. Обычно состоят из разметки и стилей, реже имеется простенькая логика (например, у выпадающего списка).

Иногда части некоторых портлетов могут мигрировать сюда, например, когда дизайн отдают частями и не сразу понятно, что блок будет использоваться в разных портлетах. Да и вообще — мне ли вам рассказывать что такое UI-Kit наборы.

Модули и полезности

Часто ли вы встречали блоки без разметки или просто с одним классом? Думаю, что да. Как раз для таких случаев и требуется модуль. Примеров немало: это может быть контролер хэшей, «аниматор», наш любимый +icon, кастомные стили какого-либо плагина и т.д.

Да, я знаю, все скрипты можно сложить в app/scripts, но куда сложить стили? Можно в app/styles, но тогда они уже будут «разбросаны», а мы же хотим, чтобы всё было по полочкам.

Контентые части

Наверняка вы сталкивались с требованием не использовать классы в контентной части страницы, чтобы контент-менеджеры клиента спокойно наполняли страницы текстами. Мы создали отдельную папку app/contents для разных примеров текстов, причем их формат может быть как Jade написанный нами, так и HTML, предложенный клиентом под стилизацию. Эта часть необходима нам только при наличии модуля content, который и отвечает за стили этих контентов.

Страницы и передача разметки бекенду

Зачастую у бекенда появляются проблемы с интеграцией разметки. Раньше у нас dist хранился в репозиториях, а с переходом на GulpJS его добавили в исключения, чтобы не было конфликтов. Сейчас все передают верстку архивом, для этого есть даже команда npm run zip, которая собирает все файлы в архив. Для нас это удобно, но бекенду не нравится «нарезать» разметку с готовой страницы. Я отказался от передачи dist в архиве.

На помощь пришла app/production с парой отличий от основной папки страниц app/pages, которая, в свою очередь, тоже была немного модифицирована. Теперь обе папки имеют вложенность (тип, страница, вид и тд.), а основным разделением является тип. Собранные страницы находятся в app/../collected, а отдельные портлеты и их модификации без основной разметки шаблона складываем в app/../portlets. Такое разделение позволяет не создавать кучу полных однотипных страниц с различными состояниями блоков.

Так как у нас забирают разметку с репозитория, продакшен мы собираем после утверждения клиентом. В случае редизайна или других правок в блоке после интеграции бекендом это позволяет видеть diff изменений в разметке.

Изменения коснулись и index.html со списком всех страниц верстки. Теперь мы группируем страницы по типу в две колонки и оставляем место для ссылки-иконки на репозиторий. Так бекенд может быстро получать разметку. Нагляднее можно посмотреть на скриншоте.

В общем ребята, делитесь опытом! Всем спасибо и до скорых встреч!

comments powered by Disqus