[Из песочницы] Вёрстка по БЭМу в Ruby on Rails
Введение В этой статье я хотел бы рассказать о технике вёрстки по БЭМу в рельсовых проектах. Я ещё не видел подобных руководств (кроме, может быть, этого, но оно мало подходит в качестве руководства и о нём ещё расскажу дальше), поэтому решил написать эту статью. Кроме того, я создал гем, который упростит интеграцию БЭМ и рельс, о нём и как его использовать я тоже напишу дальше.Подготовка Для начала вам нужно установить собственно руби и рельсы. Я предпочитаю rvm. Следуйте инструкции по установке rvm, а затем установите рельсы через команду: gem install rails Ну или можете установить рельсы отсюда, если у вас Windows.
Затем создаём новый проект через команду:
rails new some_cool_project Далее добавим гем «bem» в файл Gemfile, который находится в корне только что созданного проекта. Также я рекомендую вам добавить гемы high_voltage и slim-rails. Первый позволит создавать для верстальщика типовые страницы без каких-либо особых знаний рельс и руби, второй — великолепный шаблонизатор, который может значительно ускорить вёрстку, а также минифицировать выходной html.
Теперь выполним установку необходимых файлов для гема bem при помощи команды:
rails g bem: install Установится конфиг config/initializers/bem.rb, в котором вы можете менять технологии (изначально это scss и js) и шаблоны для генерации файлов для каждой технологии lib/bem/templates/scss.tt и lib/bem/templates/js.tt. Допустим, мы хотим использовать less в нашем проекте, тогда эту технологию нужно прописать в конфиг config/initializers/bem.rb вместо scss:
BEM.configure do |config| config.technologies = [ { : group => 'stylesheets', : extension => '.less', : name => 'less', : css_directive => '@import', : css_prefix => »'», : css_postfix => »';» }, { : group => 'javascripts', : extension => '.js', : name => 'js' } ] end Также я очень рекомендую установить конфиг для spring через команду:
rails g bem: spring Эта библиотека позволит подгружать среду в фоне, что позволит быстро генерировать блоки.
Если вы установили конфиг для spring, то выполните следующую команду:
spring stop Это команда нужна для последующей перезагрузки spring.
Теперь можно уже приступать к вёрстке.
Вёрстка В качестве примера для вёрстки, я выбрал вёрстку из этой статьи.Блоки, уровни и манифесты создаются с помощью команды bem create. Это команда принимает на вход следующие флаги (значение флагов нужно указывать через пробел после них самих):
-b создаёт или использует блок. -e создаёт или использует элемент. -m создаёт модификатор. -v значение модификатора. -l создаёт или использует уровень. -a создаёт или использует манифест. -js флаг для создания файлов javascripts технологий. -css флаг для создания файлов stylesheets технологий. Вы также можете прочитать информацию о флагах и их использовании выполнив команду:
bem help create Команда create будет создавать такуе же структуру файлов (как и тут).
Далее создадим наш будущий уровень, в котором будут подключаться наши блоки и манифест через команду:
spring bem create -l shared -a application Можно и без spring:
bem create -l shared -a application Но, как я говорил, spring будет держать среду в бэкграунде, что ускорит выполнение последующих команд.
После выполнения этой команды вы увидете в терминале сообщения о том, что создались уровни и манифесты для каждой из используемых технологий. В данном случае shared — это уровень, в котором будут находится наши блоки, а application — манифест.
Если вы заглянете в файл манифеста, то увидете, что уровен shared подключен в него строкой import 'shared/shared'; Действует простое правило — в манифестах подключаются уровни, в уровнях подключаются блоки.
Удаляем прошлый манифест app/assets/application.css, так как мы будем использовать теперь манифест app/assets/application.less
Далее создадим нужные нам блоки|элементы|модификаторы через подобные команды:
spring bem create -l shared -b clear --no-js spring bem create -l shared -b page --no-js spring bem create -l shared -b page -e head-line --no-js spring bem create -l shared -b page -e line --no-js spring bem create -l shared -b link -m menu -v active --no-js … Как видно, я указываю уровень shared, в котором будут находится блоки и ещё флаг --no-js, так как для этих блоков не будут использоваться js файлы.
После выполнения этих команд будут создаваться шаблоны, в которых уже прописан нужный нам css класс и достаточно только заполнить его подходящими свойствами.
Если вы ошиблись и написали не тот класс или включили блок не в тот уровень/манифест, всегда можно откатиться выполнив обратную команду удаления блока|элемента|модификатора|уровня через команду bem destroy. Она принимает все те же флаги, кроме --js и --css.
Далее, когда мы создадим нужные нам блоки|элементы|модификаторы, переходим к вёрстке html. Если вы установили гем high_voltage, о котором я уже писал, то достаточно будет просто создать папку:
mkdir app/views/pages В которой будут находится нужные нам вьюхи. Если вы прочитали документацию к этому гему, то вам наверняка понравилась простота подключения и отображения вьюх. Например, вам нужна вёрстка для страницы «welcome». Создаём вьюху app/views/pages/welcome.html.slim и прописываем там нужный нам html. После запуска вебсервера через команду
rails s Вы можете увидеть полученный результат по адресу localhost:3000/pages/welcome
Складываем все картинки в папку app/assets/images и все теги заменяем на рельсовые хэлперы image_tag. Адреса картинок в less файлах заменяем на image-url (хэлпер, который предоставляет гем less-rails).
К сожалению, в приведённом примере не используется js. Тем не менее шаблоны, которые предоставляются для него, позволяют легко написать нужную функцию и запустить её:
function your_function_name_initializer () { // some code }
$(function () { your_function_name_initializer (); });
$(window).bind ('page: load', function () { your_function_name_initializer (); }) Почему так? Дело в том, что начиная с 4 версии рельс, используется гем turbolinks, который значительно ускоряет отображение страниц, но добавляет некоторые особенности в инициализации js, поэтому приходится оформлять такие инициализации в виде функций и затем вызывать при этих двух событиях.
Конечный вариант перенесённой вёрстки и самого рельсового проекта можно посмотреть на гитхабе.
Альтернативы Есть также гем bem-on-rails, о статье про который я говорил в начале. Я уже было хотел использовать его, но у него есть множество минусов на данный момент, которые вынудили меня написать свой гем. Среди минусов — невозможность нормально работать с уровнями и манифестами (мне так и не удалось создать два манифеста со своими уровнями и раскидывать блоки по ним), плохочитаемый код (где-то 4 пробела в качестве таба, где-то два) и вообще невысокое качество кода (нет ни одного теста, некрасивая архитектура, такое чувство, что гем делался совсем впопыхах и туда просто накидан код и вообще мне не удалось его запустить на рельсах версии 4.1 — пришлось отправить патч), плохая документация, ну, а также, если использовать вьюшные хэлперы этого гема, то может получится такое например (простой футер): = b 'footer', content: [{ elem: 'el', elemMods: ['left'], content: ['ОАО «фирма»'] }, { elem: 'el', elemMods: ['center'], content: [{ elem: 'nav-link', tag: 'a', content: ['ссылка'] }, { elem: 'nav-link', tag: 'a', content: ['ещё сслыка']}, { elem: 'nav-link', tag: 'a', content: ['и ещё ссылка'] }] }, { elem: 'el', elemMods: ['right'], content: ['такие дела'.html_safe] }] Что явно не идёт на пользу читаемости и может запутать верстальщика.
Тем не менее, я считаю, что в целом это неплохая попытка подстраивания bem-tools под рельсы.
Есть ещё некоторые экзотические варианты встраивания ноды в рельсы, чтобы использовать нативно bem-tools через grunt, например half-pipe. Но я посчитал этот вариант весьма громоздким и непростым, поэтому не стал его рассматривать всерьёз.
И ещё, можно, конечно, использовать сами bem-tools в каком-нибудь отдельном репозитории, но процесс вёрстки и переноса при этом сильно усложнится — нужно будет писать какой-нибудь (баш)скрипт для автоматического переноса и замены урлов например, постоянно гоняя вёрстку туда и сюда. Ну это ещё ладно. Но хуже всего при этом происходит переключение с ветки на ветку в этих двух репозиториях — нужно перед запуском скрипта переноса убедиться, что мы используем правильную ветку в репозитории с рельсами и в репозитории с вёрсткой, а затем ещё и следить, когда какая ветка смержится и мержить её в другом репозитории тоже. Поэтому решение не самое хорошее.
Заключение Итак, верстальщику достаточно будет просто клепать вьюхи и блоки с css|js не обязательно зная, что там творится внутри. А бекэнд разработчик вставит нужную логику. То есть процесс вёрстки сильно упрощается.Библиотека (гем) bem, которую я написал, полностью открытая и использует самую демократичную лицензию MIT. Библиотеку я написал совсем недавно и буду рад вашим отзывам и предложениям, а также пуллреквестам на гитхаб.
Я довольно кратко обо всём написал, по каждому пункту можно написать ещё множество пояснений и рассуждений, поэтому если у вас возникнут вопросы, я с удовольствием отвечу на них в комментариях.
Ссылки https://github.com/gkopylov/bemhttps://github.com/gkopylov/bem_with_rails_and_less_example_appP.S.
На момент написания статьи использовался гем bem версии 1.0.0. На данный момент версия этого гема 1.1.0 — в ней добавлена возможность подключения блоков|элементов|модификаторов прямо в манифест. Сделано это для того, чтобы верстальщику можно было самому менять порядок подключения стилей прямо в манифесте, вместо того, чтобы подключать туда уровни.
Чтобы воспользоваться данной опцией, достаточно добавить флаг -i в команду генерации. Таким образом созданные стили подключатся сразу в манифест без создания стилей для уровня.
Ещё немного хотел написать насчёт использования директив import и require. У обеих директив есть свои плюсы и минусы. Среди плюсов у import: — можно подключать миксины и переменные— всё сливается в один файл и быстрее отдаётся браузеру, вместо множество файлов, который генерирует require (но это и минус, см. ниже)среди минусов: — трудно отлаживать css — если возникнет ошибка препроцессора, будет трудно найти место этой ошибки— не обновляются стили при изменении вложенных css файлов (для того, чтобы обновились стили нужно выполнить команду rm -rf tmp/assets/* и перезапустить рельсы)Среди плюсов require: — проще отлаживать, так как на каждый require он компилирует отдельный файл— возможность livereload injection (теоретически это сделать проще чем с импортом)среди минусов: — невозможность использования миксинов или переменных
Так что решение использовать ту или иную директиву нужно принимать обдуманно и в зависимости от проекта.
Ещё немного хотел написать почему по-дефолту я решил использовать scss. Дело в том, что в сообществе рельс sass препроцессор пользуется большей популярностью и даже по дефолту при создании нового приложения включается гем с этим препроцессором. А ещё там есть отличная фича, которая как раз подходит к подходит для БЭМ — это использование амперсанда. Уже многие в БЭМ сообществе отходят от написания отдельного файла под модификатор и пишут модификатор прямо в файле с блоком, а при помощи этого сассного амперсанда можно как раз делать такие штуки прямо в стилях для блока.