EN
vitkarpov
vitkarpov
22 января 2016

Введение

На прошлых вебинарах с Димой Белицким мы сверстали простую страницу следуя БЭМ-методологии: написали HTML и CSS, немного декларативного JavaScript, а также настроили сборку с помощью gulp.

В этом вебинаре мы получим BEMJSON имеющихся страниц, напишем простые BEMHTML-шаблоны и посмотрим на некоторые интересные возможности BEMHTML.

Итак, немного про декларативные шаблоны.

Все привыкли к декларативной природе CSS, поэтому удобно провести аналогию.

Допустим, у нас есть список:

<ul class="menu">
  <li class="menu__item">
    Привет
  <li>
  <li class="menu__item">
    BEM!
  <li>
</ul>

Чтобы задать определенный внешний вид всем элементам списка можно написать CSS:

.menu__item {
    background: red;
}

А если же хочется изменить связку ul + li, например, на nav + a? Что если это можно было бы сделать по аналогии с CSS, написав соответствующий «селектор» и просто задать другое значение свойству tag?

Так это выглядит в BEMHTML:

block('menu')(
  tag()('nav')
)

block('menu').elem('item')(
  tag()('a')
)

Чтобы иметь возможность таким образом пребразовывать HTML необходима особая декларация страницы.

BEMJSON

BEMJSON — это описание структуры страницы в терминах БЭМ на JavaScript с зарезервированными полями. Указанный ранее список в BEMJSON описывается так:

({
  block: 'menu',
  tag: 'ul',
  content: [
    {
      elem: 'item',
      tag: 'li',
      content: 'Привет'
    },
    {
      elem: 'item',
      tag: 'li',
      content: 'BEM!'
    }
  ]
})

BEMJSON компилирутся в HTML.

Избавиться от копипасты tag: 'li' поможет BEMHTML-шаблон.

block('menu')(
  tag()('ul')
)

block('menu').elem('item')(
  tag()('li')
)

BEMHTML-шаблон накладывается на BEMJSON по аналогии с тем, как CSS накладывается на DOM-дерево. На выходе — получаем HTML.

BEMJSON для наших страниц

Код — 01858d

Если есть HTML, написанный по БЭМ, то BEMJSON можно получить автоматически с помощью пакета html2bemjson

npm install html2bemjson

Сборка

Код — eef725

Далее нужно дотюнить сборку:

  • gulp научился собирать зависимости по BEMJSON, а не HTML
  • добавился таск для компиляции HTML по BEMJSON с использованием BEMHTML-шаблонов

    Вычисления во время компиляции в BEMJSON

Код — 51ec21

BEMJSON представляет собой plain JavaScript, поэтому позволяет любые вычисления во время компиляции — то, чего не достает HTML.

Например,

({
  block: 'menu',
  // построим BEMJSON списка динамически из массива текстов элементов
  content: [
    'Привет',
    'BEM!'
  ].map(function(text) {
    return {
      elem: 'item',
      content: text
    };
  })
})
({
  block: 'menu',
  // определим массив текстов динамически,
  // который будет разным при каждой генерации итогового HTML
  content: (function() {
    return Math.random() > 0.5 ? ['Привет'] : ['Привет', 'BEM!'];
  }()).map(function(text) {
    return {
      elem: 'item',
      content: text
    };
  })
})

Напишем простые BEMHTML-шаблоны

Код — 17d9a6

Упростим полученный автоматической конвертацией BEMJSON:

  • вынесем всю HTML-обвязку страницы в блок page
  • упростим представление меню в BEMJSON, сгенерировав BEMJSON самого списка элементов в шаблоне
  • напишем простой шаблон для ссылки

    Специальные возможности BEMHTML

Код — bad312

Шаблонизатор BEMHTML имеет некоторые интересные возможности:

Переопределение в зависимости от входных данных

Например, блок link должен быть представлен в HTML span-ом, а не ссылкой, если в BEMJSON не было поля url.

Переопределение на уровне переопределения

Например, менюшка на странице с Поттером должна быть в HTML представлена тегом ol, а на всех других страницах — ul. Для этого достаточно определить блок меню на уровне potter.blocks. После сборки всех шаблонов в один файл получим:

// common.blocks
block('menu')(...)

// potter.blocks
block('menu')(...)

По аналогии с CSS, последнее «правило» перебивает предыдущее.

igoradamenko
#igoradamenko
25 февраля 2016

Привет!

А подскажите, пожалуйста, можно ли сюда же ещё впилить deps, или что-то похожее, чтобы собирать зависимости? Как я понял, сейчас этого нет.

Я поискал, нашёл некоторые упоминания gulp-bem, который вроде бы умеет то, что мне нужно (например, в iamstarkov/gulp-bem-stub), но может быть есть способ использовать здесь зависимости без gulp-bem.

tadatuta
#tadatuta
25 февраля 2016

Самое простое из доступного для полноценной сборки deps на сегодняшний день — это сборка на gulp в ветке project-stub: https://github.com/bem/project-stub/blob/feature/gulp/gulpfile.js (это не gulp-bem-stub по ссылке выше — там используется альтернативная реализация депс).

Подробнее про история со сборкой на БЭМ-проектов на gulp можно почитать тут: https://github.com/bem/bem-forum-content-ru/issues/782

igoradamenko
#igoradamenko
25 февраля 2016

@tadatuta Изначально я именно с той статьи, на которую вы сослались, и начал. Но там, по сравнению с этим вебинаром, как-то много всего используется, а хотелось просто чтобы зависимости подключались.

Но спасибо за помощь, буду разбираться дальше.

weynemeynen
#weynemeynen
4 марта 2016

чуваки, выложите ваше видео беминаров, пожалуйста.
Спасибо.

igoradamenko
#igoradamenko
4 марта 2016

@weynemeynen
Первый: https://ru.bem.info/forum/-661/
Второй: https://ru.bem.info/forum/-685/
Третий: https://ru.bem.info/forum/-696/

А четвёртый сам найти не могу :с

tadatuta
#tadatuta
4 марта 2016

Есть еще пятый:
А четвертый недоступен по техническим причинам, поэтому Витя написал подробную статью.

weynemeynen
#weynemeynen
4 марта 2016

там ещё пятый должен быть с В. Гриненко

weynemeynen
#weynemeynen
4 марта 2016

вот это то что нужно.
Спасибо.

igoradamenko
#igoradamenko
4 марта 2016

@tadatuta О_О
Когда видел репозиторий по пятому, думал, это заготовка. Оказывается, когда-то пропустил бэминар. Пора навёрстывать. Спасибо за видео :)

tadatuta
#tadatuta
4 марта 2016

@igoradamenko

Оказывается, когда-то пропустил бэминар

Это, кстати, интересно — у меня есть подозрение, что не все наши письма с приглашениями долетают до пользователей :(

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

// cc @deeonis

igoradamenko
#igoradamenko
4 марта 2016

@tadatuta Подписался на рассылку после первого или второго. В 3-м и 4-м точно участвовал; письма точно приходили.

Не помню, чтобы я получал письмо про пятый. Мне кажется, что его не было, иначе я хотя бы знал о том, что бэминар состоялся.

tadatuta
#tadatuta
4 марта 2016

@igoradamenko Спасибо, будем разбираться, где мы продолбали.

ilyar
#ilyar
8 марта 2016

Есть еще пятый:

@tadatuta видео не доступно.

igoradamenko
#igoradamenko
8 марта 2016

@ilyar Уверены? У меня работает.

igoradamenko
#igoradamenko
8 марта 2016

@ilyar На всякий случай залил: https://yadi.sk/i/7dUde7j3pz8P8

ilyar
#ilyar
8 марта 2016

@igoradamenko уверен, если смотреть с форума:

баг обработки ссылки на youtube

Сейчас понял, что можно перейти по ссылке, которую видно на GitHub, тогда работает:

Есть еще пятый: https://www.youtube.com/watch?v=OBjKCY3TiJg

Спасибо!