...

вторник, 8 июля 2014 г.

[Из песочницы] Вёрстка по БЭМу в 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: ['<a href="http://ya.ru/">такие дела</a>'.html_safe] }]


Что явно не идёт на пользу читаемости и может запутать верстальщика.


Тем не менее, я считаю, что в целом это неплохая попытка подстраивания bem-tools под рельсы.


Есть ещё некоторые экзотические варианты встраивания ноды в рельсы, чтобы использовать нативно bem-tools через grunt, например half-pipe. Но я посчитал этот вариант весьма громоздким и непростым, поэтому не стал его рассматривать всерьёз.


И ещё, можно, конечно, использовать сами bem-tools в каком-нибудь отдельном репозитории, но процесс вёрстки и переноса при этом сильно усложнится — нужно будет писать какой-нибудь (баш)скрипт для автоматического переноса и замены урлов например, постоянно гоняя вёрстку туда и сюда. Ну это ещё ладно. Но хуже всего при этом происходит переключение с ветки на ветку в этих двух репозиториях — нужно перед запуском скрипта переноса убедиться, что мы используем правильную ветку в репозитории с рельсами и в репозитории с вёрсткой, а затем ещё и следить, когда какая ветка смержится и мержить её в другом репозитории тоже. Поэтому решение не самое хорошее.


Заключение




Итак, верстальщику достаточно будет просто клепать вьюхи и блоки с css|js не обязательно зная, что там творится внутри. А бекэнд разработчик вставит нужную логику. То есть процесс вёрстки сильно упрощается.

Библиотека(гем) bem, которую я написал, полностью открытая и использует самую демократичную лицензию MIT. Библиотеку я написал совсем недавно и буду рад вашим отзывам и предложениям, а также пуллреквестам на гитхаб.


Я довольно кратко обо всём написал, по каждому пункту можно написать ещё множество пояснений и рассуждений, поэтому если у вас возникнут вопросы, я с удовольствием отвечу на них в комментариях.


Ссылки




http://ift.tt/1n3sNvi

http://ift.tt/1qGuIvD

P.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 препроцессор пользуется большей популярностью и даже по дефолту при создании нового приложения включается гем с этим препроцессором. А ещё там есть отличная фича, которая как раз подходит к подходит для БЭМ — это использование амперсанда. Уже многие в БЭМ сообществе отходят от написания отдельного файла под модификатор и пишут модификатор прямо в файле с блоком, а при помощи этого сассного амперсанда можно как раз делать такие штуки прямо в стилях для блока.


This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


Комментариев нет:

Отправить комментарий