© 2021 WebHive

Создаём минимальный проект на БЭМ c нуля

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

Классическим способом установки, который крайне рекомендуют авторы БЭМ является клонирование некого каноничного репозитария с расово верным дефолтным проектом project-stub.

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

Подготовка проекта

Технология БЕМ реализована на javascript, поэтому для нашего проекта подготовим package.json

1
2
$ npm init --yes
Wrote to package.json:

Ставим ENB

В связи с тем, что решил погрузиться в пучину БЭМ полностью решил для сборки проекта использовать их родной сборщик ENB.

Казалось бы логично было бы установить пакет bem, но как оказалось в этом пакете находятся bem-tools, которые типа считаются устаревшими, а идеологически правильным всё-таки считается использование именно ENB.

Ну что — ставим:

1
$ npm install enb --save-dev

Голый ENB походу умеет только запускать сборку проекта enb make и запускать сервер enb server. Негусто, но на самом деле насколько я понимаю ENB имеет кучу расширений, которые и содержать всё самое вкусное.

Попытка запустить сборку или сервер ожидаемо выдаёт ошибку.

1
Error: Cannot find enb config directory. Should be either .enb/ or .bem/.

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

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

Тем не менее, чтобы ENB не ругался скормим ему минимальный пустой конфиг.

1
$ mkdir .bem && echo "module.exports = function(config) {};" > .bem/make.js

На этот раз enb make отрабатывает как надо (правда ничего не делает):

1
2
3
4
$ ./node_modules/.bin/enb make
21:57:28.025 - build started
21:57:28.030 - build finished - 11ms

На этом считаем, что ENB у нас установлен.

Ближе к БЭМ

Как оказалось дефолтный ENB довольно бесполезен. Нам нужен БЭМ, а не абстрактный сборщик, а для этого нам нужно установить набор технологий для БЭМ:

1
$ npm install enb-bem-techs --save-dev

Вот тут есть список технологий, предоставляемых этим пакетом.

Создаём минимальный конфиг (см. ниже) и нихрена не работает опять т. к. нужен enb-bemxjst. Да что-ж такое-то — ещё одна неявная зависимость. Тем не менее ставим — деваться некуда.

1
$ npm install enb-bemxjst --save-dev

Конфиг для ENB

Вот такой у меня получился минимальный конфиг, чтобы сгенерировать минимальный проект, который умеет генерировать только HTML. Для написания использовался project-stub и документация enb-bem-techs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
/**
* Подключаем требуемые технологии
*/
var techs = {
fileProvider: require('enb/techs/file-provider'), // источник исходных данных - файл
bemhtml: require('enb-bemxjst/techs/bemhtml'), // поддержка bemhtml
bemjsonToHtml: require('enb-bemxjst/techs/bemjson-to-html') // преобразование bemjson -> html
},
enbBemTechs = require('enb-bem-techs')

/**
* Непосредственно конфигурация
*/
module.exports = function(config) {
/**
* Указываем по каким путям мы будем искать исходники для сборки
* В нашем случае это папки '*.bundles/*'
*/
config.nodes('*.bundles/*', function(nodeConfig) {
/**
* Добавляем используемые технологии
*/
nodeConfig.addTechs([
[enbBemTechs.levels, { levels: [] }],

/**
* Генерация из bemjson -> bemdecl - т.е. из исходного bemjson-а
* вытаскиваем все используемые блоки в отдельный файл.
*/
[enbBemTechs.bemjsonToBemdecl],
/**
* Генерация из bemjson -> deps - т.е. из исходного bemjson-а
* вытаскиваем все используемые зависимости в отдельный файл.
*/
[enbBemTechs.deps],

/**
* Не совсем понял, что делает эта технология - вроде как
* объединяет сгенерированные файлы
*/
[enbBemTechs.files],

/**
* Указываем откуда брать исходную информацию.
* В данном случае используем файл и именно файл
* с расширением .bemjson.js
* Знак вопроса заменяется на имя бандла
*/
[techs.fileProvider, { target: '?.bemjson.js' }],

// https://github.com/enb/enb-bemxjst/blob/v4.1.0/api.ru.md
[techs.bemhtml],

// ну и указываем, что из bemjson-а мы будем генерировать HTML
[techs.bemjsonToHtml],
]);

nodeConfig.addTargets(['?.html']); // мы генерируем только html
});
};

Тестовый бандл

Создадим папку для нашей первой страницы

1
$ mkdir -p desktop.bundles/index

Для простоты будем использовать только desktop.bundles. Такое именование папок принято в БЭМ, поэтому буду придерживаться именно его, а не изобретать свой велосипед.

Ну и внутри созданной папки создадим файл index.bemjson.js со следующим содержимым:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
module.exports = {
block : 'page',
content : [
{
block : 'header',
content : [
'header content goes here'
]
},
{
block : 'content',
content : [
{
tag : 'p',
content : [
'main content',
]
},
]
},
{
block : 'footer',
content : [
'footer content goes here'
]
}
]
};

И запускаем билд

1
2
3
4
5
6
7
8
9
10
11
./node_modules/.bin/enb make
10:05:31.270 - build started
10:05:31.283 - [rebuild] [desktop.bundles/index/index.bemjson.js] file-provider
10:05:31.289 - [rebuild] [desktop.bundles/index/index.levels] levels
10:05:31.290 - [rebuild] [desktop.bundles/index/index.bemdecl.js] bemjson-to-bemdecl
10:05:31.294 - [rebuild] [desktop.bundles/index/index.deps.js] deps
10:05:31.295 - [rebuild] [desktop.bundles/index/index.files] files
10:05:31.295 - [rebuild] [desktop.bundles/index/index.dirs] files
10:05:31.563 - [rebuild] [desktop.bundles/index/index.bemhtml.js] bemhtml
10:05:31.594 - [rebuild] [desktop.bundles/index/index.html] bemjson-to-html
10:05:31.596 - build finished - 388ms

На выходе мы получили кучу промежуточных файлов ну и вожделенный index.html, ради которого всё и затевалось. Взглянем на него.

1
2
3
4
5
6
7
<div class="page">
<div class="header">header content goes here</div>
<div class="content">
<p>main content</p>
</div>
<div class="footer">footer content goes here</div>
</div>

Всё в соответствии с исходным bemjson-ом.

Итого

Ну что сказать — для начала неплохо. Как минимум оно работает.
В общем и целом для минимального старта необходимы следующие пакеты.

Нужен так-же конфиг для ENB — .bem/make.js

Без этого минимума сборка каких-бы то ни было HTML файлов видимо невозможна.

Не понравилось, что надо создавать довольно хитрый конфиг, что сделать непросто т. к. нужно предварительно переварить немало новых терминов и концепций. Есть конечно вариант с project-stub, но на мой взгляд там слишком много магии и мало что понятно.

Комментарии