Войти с помощью github
Форум /

Леша @zxqfox, а следом и Коля @gruzzilkin интересуются, как начать разрабатывать свою БЭМ-библиотеку.

Ответ на этот вопрос может быть разным в зависимости от того, что вы вкладываете в этот термин.

Я попробовал рассмотреть создание библиотеки от простого к сложному, постепенно добавляя фичи.

А именно:

  • Самый простой вариант, когда библиотекой является просто папка с блоками
  • Разделение библиотеки по уровням переопределения
  • Вид библиотеки после добавления документации
  • Пример файловой структуры с тестами и линтерами
  • Оформление своей библиотеки

А в конце поделился рецептом, как быстро получить себе всю инфраструктуру, которую мы используем для bem-библиотек. TL;DR

Любая папка с блоками — библиотека

В самом простом случае любая папка, в которой лежат файлы с реализацией блоков, может служить библиотекой.

Например, вот так может выглядеть полезная библиотека с блоком clearfix:

my-library/
    clearfix/
        clearfix.css

Конечно, просто копировать ее из проекта в проект не очень удобно. Поэтому стоит воспользоваться любимой системой контроля версий и опубликовать библиотеку, скажем, на github. На проекты ее удобно будет доставлять через bower.

Получим:

my-library/
    .git/
    bower.json
    clearfix/
        clearfix.css

Теперь представим, что у нас в библиотеке появился блок ua, который будет помогать с feature detection.

Хозяйке на заметку: не стоит бояться класть в библиотеку блоки, которые не будут востребованы во всех ваших проектах, ведь сборщик соберет только нужные вам блоки в каждом конкретном проекте.

Нужный блок можно реализовать несколькими способами.

Самый простой — поступить по аналогии с clearfix и положить реализацию в соответствующую папку:

my-library/
    .git/
    bower.json
    clearfix/
        clearfix.css
    ua/
        ua.js

Однако, очевидно, что для разных платформ будут нужны разные данные. Например, на мобильном устройстве нас интересует ориентация устройства, для десктопа это знание не нужно. Тогда как часть информации о user agent будет нужна на всех платформах.

Как можно избежать дублирования кода и при этом не тянуть лишний код туда, где он заведомо не нужен?

Разделение блоков по уровням переопределения

Можно воспользоваться концепцией уровней переопределения. Это может выглядеть так: один блок представляем «слоями», а каждый новый слой до- переопределяет либо какую-то часть визуальных свойств, либо доопределяет поведение блока.

В результате структура библиотеки может выглядеть так:

my-library/
    .git/
    bower.json
    common.blocks/
        clearfix/
            clearfix.css
        ua/
            ua.js
    desktop.blocks/
        ua/
            ua.js
    touch.blocks/
        ua/
            ua.js

Мы видим, что блок ua оказался разделен на общую между всеми платформами часть (она попала в common.blocks) и специфику, необходимую в конкретном окружении.

Как это работает?

Сборщик знает, какие уровни переопределения и в каком порядке мы хотим собирать для нашего проекта. Поэтому код из последующих «слоев» сможет перекрыть предыдущий.

Нагляднее всего это можно продемонстрировать на примере с CSS:

/* my-library/common.blocks/b1 */
.b1 {
    width: 150px;
    height: 50px;
}

/* my-library/desktop.blocks/b1 */
.b1 {
    font-size: 24px;
    height: 80px;
}

Здесь некий блок b1 представлен на двух уровнях: common.blocks и desktop.blocks. При этом на общем уровне ему задаются высота и ширина, на уровне desktop.blocks добавляется знание про размер шрифта, а высота переопределяется новым значением.

Если писать код определенным образом, то аналогичного эффекта можно достичь и для остальных технологий, в т.ч. JavaScript и шаблонов. Например, мы используем i-bem.js и BEMHTML(https://ru.bem.info/technology/bemhtml/), чтобы упростить себе эту задачу.

Документируем блоки библиотеки

Когда в библиотеке окажется много блоков, потребуется какое-то описание для всей библиотеки в целом. А если блоки в ней будут достаточно сложными, то хорошо бы иметь описание каждого блока отдельно. Кроме того, нужно где-то фиксировать информацию об изменениях в каждой версии библиотек.

Получим что-то вроде:

my-library/
    .git/
    bower.json
    common.blocks/
        clearfix/
            clearfix.css
            clearfix.md
        ua/
            ua.js
            ua.md
    desktop.blocks/
        ua/
            ua.js
            ua.md
    touch.blocks/
        ua/
            ua.js
            ua.md
    README.md
    CHANGELOG.md

Тестируем и следим за кодстайлом

Если работу над библиотекой ведут сразу несколько разработчиков, то нужно следить за кодстайлом, для блоков писать тесты, которые бы запускались на прекоммит-хук и в CI:

my-library/
    .csscomb.json
    .git/
    .githooks/
        pre-commit
    .jscsrc
    .jshint-groups.js
    .travis.yml
    bower.json
    common.blocks/
        clearfix/
            clearfix.css
            clearfix.md
        ua/
            ua.js
            ua.md
            ua.spec.js
    desktop.blocks/
        ua/
            ua.js
            ua.md
            ua.spec.js
    package.json # здесь задекларируем модули для сборки и тестирования
    touch.blocks/
        ua/
            ua.js
            ua.md
            ua.spec.js
    README.md
    CHANGELOG.md

Как мы оформляем bem-библиотеки

В какой-то момент для наглядного примера работы каждого блока во всей его вариативности может потребоваться демо-страница.

Я не случайно оставил за скобками всю историю про сборку таких примеров, тестов и документации по всем уровням переопределения.

Также не стоит ограничиваться unit-тестами для JavaScript, проверки требуют и шаблоны, и верстка. А для всех видов тестов в свою очередь потребуется анализ покрытия (coverage).

Для решения всех этих задач в БЭМ-платформе существуют готовые инструменты. Их достаточно много, и каждый требует какого-то времени, чтобы с ним разобраться.

Поэтому самый простой способ быстро начать разрабатывать библиотеку, а не заниматься налаживанием необходимой инфраструктуры вокруг — взять готовое.

TL;DR

Я бы предложил поступить примерно так:

git clone https://github.com/bem/bem-components.git my-library
cd $_
rm -rf *.blocks/* design

Теперь можно пользоваться ;)

Конечно, это не самый элегантный способ, но зато быстро и работает.

Мы думаем над тем, как облегчить получение готовой инфраструктуры для своей библиотеки. Решение видится в пакете-обертке над всем необходимым с удобным и лаконичным API.

Рассказывать о ней планируем в нашем блоге. Stay BEMed!