Доброго времени суток! С вами один из ведущих разработчиков 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
со списком всех страниц верстки. Теперь мы группируем страницы по типу в две колонки и оставляем место для ссылки-иконки на репозиторий. Так бекенд может быстро получать разметку. Нагляднее можно посмотреть на скриншоте.
В общем ребята, делитесь опытом! Всем спасибо и до скорых встреч!