Несколько раз пытался пощупать БЭМ, но порог входа довольно высок, поэтому раз за разом бросал это дело, хотя внутренне понимал, что рациональное зерно в этом есть. На этот раз решил погрузиться полностью и попробовать собрать проект на полном стеке технологий БЭМ
Классическим способом установки, который крайне рекомендуют авторы БЭМ является клонирование некого каноничного репозитария с расово верным дефолтным проектом project-stub.
Но это не мой метод — я предпочитаю понимать, что я делаю, а не копипастить какие-то непонятные решения, которые магическим образом работают, но только непонятно как. Поэтому попробую шаг за шагом установить все библиотеки и зависимости с нуля и заодно пройтись по всем граблям. Полагаю это будет способствовать более глубокому пониманию внутренностей БЭМ, что собственно мне и нужно.
Подготовка проекта
Технология БЕМ реализована на javascript, поэтому для нашего проекта подготовим package.json
$ npm init --yes
Wrote to package.json:
Ставим ENB
В связи с тем, что решил погрузиться в пучину БЭМ полностью решил для сборки проекта использовать их родной сборщик ENB.
Казалось бы логично было бы установить пакет bem, но как оказалось в этом пакете находятся bem-tools, которые типа считаются устаревшими, а идеологически правильным всё-таки считается использование именно ENB.
Ну что — ставим:
$ npm install enb --save-dev
Голый ENB походу умеет только запускать сборку проекта enb make и запускать сервер enb server. Негусто, но на самом деле насколько я понимаю ENB имеет кучу расширений, которые и содержать всё самое вкусное.
Попытка запустить сборку или сервер ожидаемо выдаёт ошибку.
Error: Cannot find enb config directory. Should be either .enb/ or .bem/.
что впрочем вполне логично, хотя я бы конечно предпочёл, чтобы создавался какой-то дефолтный конфиг с комментариями, с которого было бы значительно проще начать. Хотя подход с отсутствием конфигов довольно распространён в среде отечественных разработчиков — типа всё так офигенно гибко, что даже дефолтные настройки будут недостаточно гибки.
Попробуем всё-таки написать конфиг. По счастью есть исчерпывающее руководство — Как-собрать-проект—пошаговое-руководство. Не очень понятно почему его нет в официальной документации … уже понятно — всё устарело, примеры не работают, полная дезинформация.
Тем не менее, чтобы ENB не ругался скормим ему минимальный пустой конфиг.
$ mkdir .bem && echo "module.exports = function(config) {};" > .bem/make.js
На этот раз enb make отрабатывает как надо (правда ничего не делает):
$ ./node_modules/.bin/enb make
21:57:28.025 - build started
21:57:28.030 - build finished - 11ms
На этом считаем, что ENB у нас установлен.
Ближе к БЭМ
Как оказалось дефолтный ENB довольно бесполезен. Нам нужен БЭМ, а не абстрактный сборщик, а для этого нам нужно установить набор технологий для БЭМ:
$ npm install enb-bem-techs --save-dev
Вот тут есть список технологий, предоставляемых этим пакетом.
Создаём минимальный конфиг (см. ниже) и нихрена не работает опять т. к. нужен enb-bemxjst. Да что-ж такое-то — ещё одна неявная зависимость. Тем не менее ставим — деваться некуда.
$ npm install enb-bemxjst --save-dev
Конфиг для ENB
Вот такой у меня получился минимальный конфиг, чтобы сгенерировать минимальный проект, который умеет генерировать только HTML. Для написания использовался project-stub и документация enb-bem-techs
/**
* Подключаем требуемые технологии
*/
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
});
};
Тестовый бандл
Создадим папку для нашей первой страницы
$ mkdir -p desktop.bundles/index
Для простоты будем использовать только desktop.bundles. Такое именование папок принято в БЭМ, поэтому буду придерживаться именно его, а не изобретать свой велосипед.
Ну и внутри созданной папки создадим файл index.bemjson.js со следующим содержимым:
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'
]
}
]
};
И запускаем билд
./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, ради которого всё и затевалось. Взглянем на него.
<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 (https://github.com/enb/enb)
- enb-bem-techs (https://github.com/enb/enb-bem-techs)
- enb-bemxjst (https://github.com/enb/enb-bemxjst)
Нужен так-же конфиг для ENB — .bem/make.js
Без этого минимума сборка каких-бы то ни было HTML файлов видимо невозможна.
Не понравилось, что надо создавать довольно хитрый конфиг, что сделать непросто т. к. нужно предварительно переварить немало новых терминов и концепций. Есть конечно вариант с project-stub, но на мой взгляд там слишком много магии и мало что понятно.
Комментарии