EN
БЭМ. Блок, Элемент, МодификаторИнструментыСборкаbem-toolsМодули технологий

Модули технологий

Модули технологий. Создание и использование

Общие понятия

Технологии в БЭМ

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

Например, в папке блока «Кнопка» могут располагаться CSS-файл, описывающий внешний вид кнопки, и JS-файл, содержащий сценарий, который выполняется при нажатии на эту кнопку. Пользуясь БЭМ-терминологией можно сказать, что блок «Кнопка» реализован в технологиях CSS и JS.

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

Технологии в bem-tools

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

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

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

Файлы технологии, чаще всего, идентифицируются модулем на основании суффиксов. Суффиксом в bem-tools считается часть имени файла, следующая после первой точки в его названии.

Особенности архитектуры пакета bem-tools

Для БЭМ-проектов характерен двоякий набор задач при работе с файлами технологий.

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

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

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

.button__icon
{
}

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

Для автоматизации этих задач служит команда bem create. Она же используется, если нужно совершить действие с единичным файлом технологии. Например, преобразовать его в файл другой технологии. Так, можно создать модуль технологии, позволяющий преобразовывать PNG в JPG или XML в JSON.

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

Бандл (от англ. bundle — вязанка, пакет) — совокупность результирующих файлов технологий, собранных из файлов технологий блоков на уровнях переопределения. Каждый отдельный результирующий файл технологии называется бандлом технологии.

Для сборки служит команда bem build. У команды есть два обязательных аргумента:

  • массив уровней переопределения, передаваемый пользователем в качестве аргумента
  • декларация сборки.

Декларация — это файл с описанием БЭМ-сущностей, собираемых командой bem build. Подробнее о форматах декларации читайте в приложении 2.

Таким образом, механизм для решения двух типов задач, характерных для БЭМ-проектов, был реализован в архитектуре пакета bem-tools в виде команд bem create и bem build:

  • за создание/преобразование единичных файлов технологии отвечает команда bem create
  • за процесс сборки отвечает команда bem build.

В процессе создания модулей технологий из всех команд, входящих в пакет bem-tools, ключевыми являются именно bem create и bem build. Команды bem make и bem server — надстройки над ними. Это означает, что модули технологий, созданные для bem create и bem build, используются также командами bem make и bem server:

  • bem make, на основании конфигурационного файла сборки проекта make.js, вызывает команды bem build и bem create с нужными аргументами, чтобы собрать бандлы всех нужных технологий проекта;
  • bem server принимает запросы на порту или сокете, передает их команде bem make, а результат сборки возвращает в качестве ответа.

Кроме упомянутых выше, в пакет bem-tools входят команды:

  • bem decl – позволяет манипулировать декларацией сборки
  • bem create level – предназначена для создания уровней переопределения.

Архитектура этих команд не предполагает возможности расширения с помощью модулей технологий.

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

В bem-tools такая возможность реализована следующим образом:

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

Базовая технология — это Node.js модуль, реализующий наиболее общую функциональность обработки данных командами bem create и bem build.

Базовая технология bem-tools реализует API технологии.

API технологии — это набор методов для работы с технологиями, общий для всех подпрограмм пакета bem-tools и модулей технологий. API реализовано в классе технологии Tech.

Базовая технология служит основой для модулей технологии. Модули переопределяют методы API технологии, реализованные в базовой технологии. Методы API, которые модулем технологии не переопределялись, будут работать в соответствии с базовой технологией.

Например, если вызвать команды bem create или bem build с произвольным именем технологии FOO в качестве опции, их поведение будет идентично базовой технологии. Предполагается, что модуля технологии FOO при этом не существует, а значит, никакие методы базовой технологии не были переопределены. В этом случае поведение команд будет следующим:

  • команда bem create создаст для БЭМ-сущностей пустые файлы с расширением .foo
  • команда bem build соберет FOO-файлы бандлов технологии, в которых отдельными строками будут прописаны пути к FOO-файлам блоков.

В пакет bem-tools входит ряд готовых - стандартных - модулей технологий. С их помощью реализованы поддержка наиболее востребованных в БЭМ-проектах технологий (таких как CSS или JS) и часть функциональности пакета — работа с зависимостями бандла, создание уровней переопределения и т.п.

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

Библиотеки блоков, такие как bem-bl или bem-core, содержат собственный набор стандартных модулей технологий. Они реализуют логику, необходимую для сборки блоков библиотек.

NB Реализации стандартных модулей технологий библиотек блоков могут отличаться от реализаций аналогичных стандартных модулей в bem-tools.

Подробнее о стандартных модулях bem-tools можно узнать из Приложения 1.

Модули технологий

Модули технологий определяют поведение команд bem create и bem build. Они добавляют к функциональности bem-tools возможность работы с новыми типами данных.

Можно рассматривать команды bem create и bem build как независимые подпрограммы пакета bem build, каждая из которых предоставляет собственный API. Модуль технологии — адаптер, реализующий API технологии команд bem create и bem build.

Переопределяя методы API, модули технологии реализуют дополнительную функциональность, необходимую для работы с соответствующими типами данных.

Также, модули технологий позволяют изменять и расширять функциональность уже существующих технологий.

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

Принцип работы

Пользователь вызывает команду bem create или bem build, передает ей набор параметров, и в качестве опции -t, --tech (-T, --force-tech) — названия технологий, используя которые нужно выполнить эти команды.

Команда создает экземпляр объекта технологии, у которого вызывается один из методов API. Для команды bem create вызывается метод createByDecl, для команды bem buildbuildByDecl.

После этого начинает работать модуль соответствующей технологии. Механизм его действия зависит от того, какие методы API объекта технологии были переопределены в модуле.

Задачи, решаемые модулями технологий

Создание и преобразование файлов технологий

Шаблон файлов, создаваемых командой bem create, определяется модулем технологии. Модуль задает:

  • суффикс создаваемых файлов
  • данные, которые будут записаны в них при создании.

Кроме статических данных, в шаблоне может использоваться контекст, относящийся к создаваемой БЭМ-сущности. В основных методах класса технологии контекст доступен в виде аргумента vars. Аргумент vars конструируется на начальном этапе выполнения базовой технологии команды bem create и доступен из всех ее методов. В нем содержится хеш опций, относящихся к текущей БЭМ-сущности, создаваемой командой bem create:

  {
opts: { args: [массив аргументов], force: true // перезаписывать существующие файлы
   },
  BlockName: 'b-my-block',   // имя блока
  Prefix: 'pages/block-name/block-name', //префикс пути к создаваемой БЭМ-сущности
  ElemName: 'elem1',   // название элемента
  ModName: 'mod1',    // название модификатора
  ModVal: 'val1'            //  значение модификатора
  }

Префикс — это путь и имя файла без суффикса. Например, для файла pages/block-name/block-name.js префиксом будет pages/block-name/block-name.

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

Сборка и обработка файлов технологий

Сборка и обработка файлов технологий производятся командой bem build. К наиболее типичным задачам, решаемым командой, относятся:

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

Для команды bem build модуль технологии определяет:

  • суффиксы исходных и результирующих файлов
  • действия, производимые над содержимым обрабатываемых файлов
  • способ преобразования декларации, на основании которой производятся действия с файлами. В базовой технологии преобразований декларации не осуществляется, однако такая возможность заложена в API.

Размещение

Пользовательские модули технологий рекомендуется размещать в каталоге .bem/techs, находящемся в корневом каталоге проекта или уровня переопределения. Стандартные модули технологий bem-tools находятся в каталоге lib/techs.

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

Подключение

Чтобы подключить к уровню переопределения проекта пользовательский модуль технологии FOO, нужно зарегистрировать его в файле .bem/level.js. Этот файл должен экспортировать функцию getTechs(), которая возвращает объект. В ключах объекта содержатся имена технологий, используемых на текущем уровне переопределения, а в значениях — пути до соответствующих модулей технологий.

exports.getTechs = function() {
    return {
        'foo': require.resolve('../../.bem/techs/foo.js') // путь к модулю технологии
    };
};

Отметим, что функция require.resolve() проверяет наличие файла модуля технологии по указанному пути. Если путь был задан в виде 'foo': '../../.bem/techs/foo.js', то при отсутствии файла по указанному пути поведение технологии будет идентично базовой.

NB Пути указываются относительно того модуля, в котором они заданы. В случае из примера, точкой отсчета будет модуль .bem/level.js.

Создание модуля технологии

Есть два рекомендованных пути создания модулей технологии:

  • можно расширять базовую технологию, реализованную в модуле lib/tech.js
  • или взять за основу готовый модуль технологии.

    В bem-tools для организации наследования используется модуль inherit. Поэтому, при написании модуля технологии, через this.__base(...) можно вызвать метод одного из базовых классов, а к классу технологии можно обратиться через this.__class.

На основе базовой технологии

Модуль, создаваемый на основе базовой технологии, должен экспортировать объект techMixin. Методы этого объекта переопределят методы базового класса технологии Tech.

exports.techMixin = {

    getCreateResult: function(...) {
        // ваш код
    } };

На основе готовой технологии

Использовать готовый модуль технологии как основу можно двумя способами: задав имя технологии или указав путь к ее модулю. Рассмотрим эти способы подробнее.

По имени

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

Этот способ подходит для случаев:

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

exports.baseTechName = 'css';
exports.techMixin = { /* ... /* };

В этом примере новая технология будет расширять технологию CSS, заданную на уровне переопределения. Если на уровне переопределения технология CSS не задана, будет расширена технология CSS из набора стандартных модулей технологий пакета bem-tools.

По пути

Чтобы взять за основу готовый модуль технологии по пути, нужно добавить к экспортируемым функциям переменную baseTechPath. В ней задается абсолютный путь к расширяемому модулю.

Этот способ подходит для случаев:

  • когда одну пользовательскую технологию расширяют с помощью другой. Например, если существует модуль технологии, обладающий некоторой базовой функциональностью, которую в разных проектах удобно расширять специфическим для проекта набором правил.
  • когда технология используется на нескольких уровнях и надо быть уверенным, что расширяться будет конкретная реализация. Например, если в проекте используется модифицированная технология из набора стандартных модулей и надо расширить ее, а не стандартную реализацию.
exports.baseTechPath = '/абсолютный/путь/до/модуля/технологии/css';
exports.techMixin = { /* ... /* };

Версии API технологии

В пакете bem-tools с версии 0.6.4 было обновлено API технологии, используемое при написании модулей технологий. В дальнейшем будем называть обновленное API технологии v2, а старое v1.

Изложенное в предыдущих разделах верно как для модулей, реализованных с поддержкой API v1, так и для модулей с API v2.

NB Было изменено только API технологии для команды bem build.

С изменениями в технологии API v2 можно ознакомиться в разделах:

Работа с API v2 технологии

В новой версии bem-tools реализована обратная совместимость с модулями технологий, использующими API v1. Тем не менее, новая версия API позволяет ускорить сборку проекта командами bem make и bem server. Прирост скорости зависит от специфики проекта и может варьироваться в диапазоне от нескольких процентов до десятка раз.

Чтобы ускорить сборку вашего проекта, нужно использовать модули технологий, реализующие API v2.

Для начала работы с обновленным API рекомендуется воспользоваться версией project-stub, использующей API v2.

На данный момент поддержка API v2 технологии добавлена:

  • в ветку master project-stub'а
  • в библиотеку блоков bem-core.

При расширении одного модуля технологии другим, все модули в цепочке наследования должны использовать API одной версии (модули API v1 не должны перемешиваться с модулями API v2).

Стандартные модули технологий и API v2

В новой версии bem-tools был добавлен набор стандартных модулей технологий, поддерживающих API v2. Таким образом, в пакете имеется два набора стандартных модулей: v1 и v2. Для использования стандартных модулей технологии c поддержкой API v2 нужно декларировать их в файле .bem/level.js проекта. Например:

exports.getTechs = function() {

    return {
        'bemjson.js'     : '/lib/tech/v2',
        'js'             : 'v2/js-i',
        'bemdecl.js'     : 'v2/bemdecl.js',
        'deps.js'        : 'v2/deps.js',
        'i18n'           : '../bem-bl/blocks-common/i-bem/bem/techs/v2/i18n.js',
        'i18n.js'        : '../bem-bl/blocks-common/i-bem/bem/techs/v2/i18n.js.js',
        'css'            : 'v2/css'
    };
};

Если в файле level.js уровня переопределения стандартные модули технологий задекларированы не были, то по умолчанию будет использоваться API v1. Для использования API v2 путь к стандартным модулям технологий v2 должен быть задан явно, как показано в примере выше.

Модули технологий, использующие API v1, будут работать с новой версией bem-tools без прироста скорости. Это относится как к стандартным модулям технологий, идущим в составе bem-tools, так и к тем, которые входят в библиотеку bem-bl.

Кэширование сборки

Использование в проекте модулей технологии v2 позволяет повысить производительность сборки за счет кэширования уровней переопределения блоков.

Если в вашем проекте подключается bem-bl или другая библиотека блоков, блоки которой вы не меняете, то сборку можно настроить таким образом, чтобы библиотека просканировалась единожды, и при последующих сборках использовался кэш с диска.

Сделать это можно с помощью следующего кода в файле .bem/make.js:

MAKE.decl('Arch', {
    getLevelCachePolicy: function() {
        return {
                cache: false,
                except: ['bem-bl']
        }
    }

});

Здесь cache:false означает, что по умолчанию кэш уровней выключен. except — массив путей уровней переопределения, для которых будет действовать исключение, т.е. в данном случае кэш будет включен.

Если сборка запущена с опцией --force, содержимое кэша обновляется.

NB По умолчанию кэширование сборки отключено.

Настройка модуля технологии для использования API v2

Чтобы в модуле технологии включить поддержку API v2, модуль должен экспортировать свойство API_VER:

exports.API_VER = 2;

exports.techMixin = {

...

};

Настройка работы с суффиксами

Как уже упоминалось, суффиксы используются модулями технологий для идентификации файлов технологий. В API v1 для указания суффиксов, с которыми работает модуль технологии, использовались методы getSuffixes() и getBuildSuffixes().

В API v2 эти методы сохранились, но, для большей гибкости при работе с суффиксами, рекомендуется использовать метод getBuildSuffixesMap(). Этот метод позволяет указать как суффиксы собираемых файлов технологии, так и суффиксы файлов бандла технологии. Кроме того, он позволяет модулю технологии собирать файлы технологии с несколькими суффиксами.

{
    getBuildSuffixesMap: function() {
        return {
            'ie.css': ['ie.css', 'ie.hover.css'];
        }
    }
}

Код из примера будет собирать файл бандла с суффиксом ie.css из файлов с суффиксами ie.css и ie.hover.css.

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

Валидация файлов при последующих сборках

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

В API v1 проверка валидности собираемого файла выполнялась с помощью процедуры bem make, точнее — кодом в классе BemBuildNode.

В API v2 эта задача переложена на модули технологий. Модуль может самостоятельно проверить валидность собираемых файлов, опираясь на знания о суффиксах исходных и результирующих файлов технологии.

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

В базовой технологии v2 логика валидации реализована в методе getBuildResults(decl, levels, output, opts). Для определения того, нужно ли вызывать getBuildResult(files, suffix, output, opts) (то есть непосредственно собрать файл бандла технологии с текущим суффиксом), метод получает список файлов, которые должны быть включены в сборку. Затем он проверяет возвращаемое для этого списка значение метода validate(file, filteredFiles, opts). При значении true файл бандла считается валидным и не пересобирается.

Метод validate(file, filteredFiles, opts) принимает следующие аргументы:

  • {String} file — абсолютный путь к собираемому файлу
  • {Array} filteredFiles — список файлов, которые должны попасть в сборку
  • {Object} opts — хеш опциональных параметров, сюда передается аргумент opts, приходящий в getBuildResults.

Если в opts содержится ключ force со значением true, метод validate вернет false. Метод validate загружает из кэша (.bem/cache) список файлов, из которых в последний раз собирался результирующий файл, и сравнивает его со значением параметра filteredFiles. Если отличий нет, считается, что результирующий файл валиден.

Для получения списка файлов, попавших в предыдущую сборку, используется метод getLastUsedData(file), для сохранения в кэш — saveLastUsedData(file, data). Аргументы:

  • {String} file — абсолютный путь к файлу, кэш которого нужно загрузить или сохранить
  • {Object} data — объект со списком файлов, который сохранится в кэш в виде JSON.

В большинстве случаев для валидации достаточно логики, заложенной в базовую технологию v2. Если ваш модуль технологии производит сборку файлов на основании суффиксов из getBuildSuffixesMap() и не подмешивает в результирующий файл сторонний контент, то, вероятнее всего, писать специальную логику для валидации нет необходимости.

Рекомендации по созданию модулей технологий

Общие рекомендации

В процессе создания модуля технологии нужно отдельно переопределить поведение базовой технологии для команд bem create и bem build.

NB Модуль технологии может изменять поведение базовой технологии как обеих команд, так и любой из них по отдельности.

Чтобы изменить поведение базовой технологии, нужно в создаваемом модуле переопределить один или несколько методов из стандартной цепочки вызовов базовой технологии.

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

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

С полным перечнем методов базовой технологии можно ознакомиться в исходном коде:

Методы, рекомендованные для переопределения

Для команды bem create

create(prefix, vars, force)

Аргументы:

  • {String} prefix — префикс создаваемого файла технологии
  • {Object} vars — словарь, содержащий сведения о создаваемой БЭМ-сущности: имя блока, элемента, модификатора, значение модификатора, префикс.

Хеш vars имеет следующую структуру:

opts:
    {
    args: [],  // массив аргументов
    force: true // перезаписывать существующие файлы
    },
      BlockName: 'b_my_block',   // имя блока
      Prefix: 'pages/block_name/block_name', //префикс пути к создаваемой БЭМ-сущности
     ElemName: 'elem1',   // название элемента
      ModName: 'mod1',    // название модификатора
      ModVal: 'val1'            //  значение модификатора
  • {Boolean} force — булева переменная, определяющая, нужно ли перезаписывать создаваемые файлы, если они уже существуют на диске.

Возвращаемое значение: Промис со значением undefined в случае успешного выполнения метода, промис с ошибкой в случае неудачи.

Описание: Метод отвечает за общий процесс формирования и сохранения содержимого создаваемых файлов технологий.

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

Поведение в базовой технологии: Метод формирует содержимое создаваемых файлов технологий для всех суффиксов с помощью метода getCreateResults(prefix, vars), затем сохраняет его на диске с помощью `storeCreateResults(prefix, res, force)``.

getCreateSuffixes()

Аргументы: -

Возвращаемое значение: {Array} Суффиксы создаваемых файлов.

Описание: Позволяет настроить работу с суффиксами для команды bem create.

Используется: Если нужно, чтобы команды bem create и bem build работали с разными суффиксами. Например, когда команда bem build должна собирать из блоков файлы с несколькими суффиксами, а команда bem create должна создавать файлы технологии с одним определенным суффиксом.

Поведение в базовой технологии: Возвращает массив с одним элементом — именем технологии.

Пример: Содержание листинга взято из модуля технологии JS+COFFEE. Этот модуль технологии собирает из блоков файлы, написанные на CoffeeScript и JavaScript в общий бандл технологии. При этом CoffeeScript транслируется в JavaScript. Модуль технологии работает с исходными файлами с двумя разными суффиксами: js и coffee. Бандл технологии собирается с общим суффиксом js.

exports.techMixin = {

    getSuffixes: function() {
        return ['js', 'coffee'];
    },

    getCreateSuffixes: function() {
        return ['coffee'];
    } }

Как видно из примера, при вызове команды bem create, файл технологии будет создан с суффиксом coffee.

getCreateResult(path, suffix, vars)

Аргументы:

  • {String} path — полный путь к файлу, включая имя и расширение
  • {String} suffix — суффикс создаваемого файла
  • {String} vars — словарь контекста, содержащий сведения о создаваемой БЭМ-сущности.

Хеш vars имеет следующую структуру:

opts:
    {
    args: [],  // массив аргументов
    force: true // инвалидатор сборки
    },
      BlockName: 'b_my_block',   // имя блока
      Prefix: 'pages/block_name/block_name', //префикс пути к создаваемой БЭМ-сущности
     ElemName: 'elem1',   // название элемента
      ModName: 'mod1',    // название модификатора
      ModVal: 'val1'            // значение модификатора

Возвращаемое значение: {String} Промис с содержимым создаваемого файла.

Описание: Метод отвечает за формирование содержимого файла с текущим суффиксом.

Используется: Когда нужно задать содержимое файла, создаваемого командой bem create.

Поведение в базовой технологии: Возвращает промис с пустой строкой.

Пример: CSS-селектор. Этот метод используется в модуле стандартной технологии CSS. Там с помощью vars конструируется селектор класса, соответствующий создаваемой БЭМ-сущности. Команда bem create block -T CSS b-my-block создаст файл со следующим содержимым:

.b-my-block
{
}

В модуле технологии CSS метод переопределен следующим образом:


var Template = require('../template'),
export.techMixin = {

    getCreateResult: function(path, suffix, vars) {

        vars.Selector = '.' + vars.BlockName +
            (vars.ElemName? '__' + vars.ElemName : '') +
            (vars.ModVal? '_' + vars.ModName + '_' + vars.ModVal : '');

        return Template.process([
            '{{bemSelector}}',
            '{',
            '}'],
            vars);

    } }

Для команды bem build с API v2

buildByDecl(decl, levels, output, opts)

Аргументы:

  • {Object} decl — декларация сборки. Содержит сведениия о блоках, элементах и модификаторах, задействованных в сборке.
  • {Level[]} levels — массив уровней переопределения, с которых метод будет осуществлять сборку.
  • {String} output — префикс пути к собираемому файлу бандла технологии. Передается в абсолютном виде.
  • {Object} opts — опции сборки. Хеш с опциями сборки, переданными пользователем. Среди них opts.force — логическая переменная, указывающая на необходимость принудительной пересборки бандла. К хешу можно добавлять пользовательские поля.

Возвращаемое значение: Промис со значением undefined в случае успешного выполнения метода, промис с ошибкой в случае неудачи.

Описание: Метод определяет основной порядок выполнения команды bem build.

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

Поведение в базовой технологии: Вызывает transformBuildDecl для преобразования декларации сборки. После этого с помощью метода getBuildResults(decl, levels, output, opts) формирует хеш результатов сборки res, который затем передает методу storeBuildResults(prefix, res) для сохранения.

transformBuildDecl(decl)

Аргументы:

  • {Object} decl — исходная декларация сборки.

Возвращаемое значение: {Object} промис с преобразованной декларацией.

Описание: Метод предназаначен для трансформации входной декларации сборки.

Используется: В случаях, когда нужно совершать какие-либо манипуляции с входной декларацией сборки.

Поведение в базовой технологии: Метод возвращает промис со входной декларацией. Никаких изменений декларации не производится.

getBuildResults(decl, levels, output, opts)

Аргументы:

  • {Promise * Object} decl — декларация сборки
  • {Object[]} levels — массив уровней переопределения, блоки которых участвуют в сборке
  • {String} output — префикс собираемого бандла
  • {Object} opts — хеш с опциями сборки, переданными пользователем.

Возвращаемое значение: {Promise * Object} промис с хешем содержимого бандла технологии для всех суффиксов, участвующих в сборке. В ключах хеша находятся суффиксы создаваемых файлов бандла технологии, в значениях — содержимое соответствующих файлов бандла.

Описание: Метод отвечает за формирование содержимого файлов бандла для всех суффиксов, участвующих в сборке. Также с его помощью осуществляется валидация сборки.

Используется: Когда нужно изменить общий процесс формирования содержимого или механизм валидации сборки.

Поведение в базовой технологии: С помощью метода getBuildPaths(decl, levels) получает список фактически существующих файлов, участвующих в сборке.

Затем проверяется значение метода validate(file, filteredFiles, opts), возвращаемое для списка собираемых файлов. При значении true существующий файл бандла считается валидным и дальнейшая сборка прекращается.

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

Метод getBuildResults возвращает хеш с результатами выполнения метода getBuildResult. В ключах хеша — суффиксы создаваемых файлов бандла технологии, а в значениях содержимое файла бандла с соответствующим суффиксом.

getBuildResult(files, suffix, output, opts)

Аргументы:

  • {Promise * String[]} files — промис, содержащий массив строк с путями к собираемым файлам
  • {String} suffix — суффикс, для которого производится сборка
  • {String} output — префикс собираемого бандла
  • {Object} opts — хеш с опциями сборки, переданными пользователем.

Возвращаемое значение: {String} промис с содержимым бандла технологии для текущего суффикса.

Описание: Метод отвечает за сборку фрагмента содержимого бандла для текущего суффикса.

Используется: Когда нужно производить действия с содержимым бандла технологии, относящимся к одному суффиксу. Например, изменить порядок включения фрагментов, полученных из исходных файлов, или поместить весь бандл технологии внутрь какой-нибудь конструкции. Например, HTML-код внутрь тегов <html> ... </html>.

Поведение в базовой технологии: Для каждого файла, расположенного по путям из files, вызывается метод getBuildResultChunk(relPath, path, suffix), формирующий фрагмент содержимого бандла, относящийся к текущему исходному файлу технологии. Результаты выполнения метода getBuildResultChunk накапливаются в массив и возвращаются в виде промиса.

getBuildResultChunk(relPath, path, suffix)

Аргументы:

  • {String} relPath — относительный путь к обрабатываемому файлу технологии
  • {String} path — абсолютный путь к обрабатываемому файлу технологии
  • {String} suffix — суффикс обрабатываемого файла технологии.

Возвращаемое значение: {String} фрагмент данных, относящихся к исходному файлу. В зависимости от технологии это может быть содержимое файла или путь к нему.

Описание: Метод служит для формирования фрагмента данных, относящихся к одному исходному файлу.

Используется: Когда нужно производить манипуляции с содержимым исходных файлов технологии перед его записью в файл бандла. Метод позволяет решать следующие задачи:

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

Поведение в базовой технологии: Возвращает строку, содержащую относительный путь к обрабатываемому файлу.

Пример: Технология CSS из набора стандартных модулей использует этот метод для того, чтобы поместить путь к CSS-файлу в конструкцию @import url('...').

exports.techMixin = {

    getBuildResultChunk: function(relPath, path, suffix) {
        return '@import url(' + relPath + ');\n';
    } };
getBuildSuffixesMap()

Аргументы: -

Возвращаемое значение: {Object} Хеш с суффиксами. В ключах хеша суффиксы собираемых бандлов, в значениях – массив суффиксов исходных файлов технологии.

Описание: Позволяет указать суффиксы исходных и результирующих файлов технологии для команды bem build.

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

Поведение в базовой технологии: Возвращает хеш, содержащий:

  • в ключе — имя технологии, полученное из this.techName. Выступает в качестве суффикса бандла.
  • в значении — массив, состоящий из одного элемента. Им является это же, полученное из this.techName, имя технологии. Оно выступает в качестве суффикса исходных файлов, собираемых технологией.

Пример: В качестве примера рассмотрим стандартный модуль технологии bemhtml.js.

    getBuildSuffixesMap: function() {
        return {
            'bemhtml.js': ['bemhtml', 'bemhtml.xjst']
        };
    },

Из кода в листинге следует, что модуль технологии будет собирать файлы с суффиксами bemhtml и bemhtml.xjst в файл бандла с суффиксом bemhtml.js.

getBuildPaths(decl, levels)

Аргументы:

  • {Promise * Object} decl — декларация сборки
  • {Object[]} levels — массив уровней переопределения, блоки с которых участвуют в сборке.

Возвращаемое значение: {Object} Хеш со списком файлов, участвующих в сборке. В ключах хеша — суффиксы собираемых файлов технологии, а в значениях – массив путей к исходным файлам технологии с соответствующим суффиксом.

Описание: Метод-хелпер. Полезен как вспомогательный метод для получения списка фактически существующих файлов, попадающих в сборку. По переданной декларации (decl) и списку уровней (levels) возвращает список существующих на них файлов, попадающих под декларацию.

Поведение в базовой технологии: По переданной декларации (decl) и списку уровней (levels) возвращает список существующих на них файлов, попадающих под декларацию.

saveLastUsedData(file, data)

Аргументы:

  • {String} file — полный путь к собираемому файлу бандла технологии
  • {Array} data — массив путей к файлам технологии, участвующим в сборке.

Возвращаемое значение: -

Описание: Метод-хелпер. Сохраняет в кэш список файлов, из которых технология строила файл бандла (file) в последний раз. Полезен как вспомогательный метод.

Поведение в базовой технологии: Участвует в процессе валидации сборки.

getLastUsedData(file)

Аргументы:

  • {String} file — полный путь к собираемому файлу бандла технологии.

Возвращаемое значение: {Object} Хеш со списком файлов, из которых технология строила файл бандла (file) в последний раз.

Описание: Метод-хелпер. Полезен как вспомогательный метод. Получает из кэша список файлов, из которых в последний раз строился бандл (file). Метод использует список, сохраненный с помощью saveLastUsedData.

Поведение в базовой технологии: Участвует в процессе валидации сборки.

Для команды bem build c API v1

NB: API v1 на данный момент морально устарело и не рекомендуется к использованию в процессе разработки. Раздел приводится в качестве справочной информации для тех, кто уже использует модули технологии с API v1.

build(prefixes, outputDir, outputName)

Аргументы:

  • {Array} prefixes — промис с массивом префиксов исходных файлов технологии. Префикс каждого из собираемых файлов технологии записывается в массив отдельной строкой.
  • {Array} outputDir — каталог, в котором собирается бандл технологии.
  • {String} outputName — имя собираемого бандла технологии.

Возвращаемое значение: Промис со значением undefined в случае успешного выполнения метода, промис с ошибкой в случае неудачи.

Описание: Метод определяет основной порядок выполнения базовой технологии bem build.

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

Поведение в базовой технологии: С помощью метода getBuildResults(prefixes, outputDir, outputName) формирует объект результатов сборки res, который затем передает методу storeBuildResults(prefix, res) для сохранения.

transformBuildDecl(decl)

Аргументы:

  • {Object} decl — исходная декларация сборки.

Возвращаемое значение: {Object} промис с преобразованной декларацией.

Описание: Метод предназаначен для трансформации входной декларации сборки.

Используется: В случаях, когда нужно совершать какие-либо манипуляции с входной декларацией сборки.

Поведение в базовой технологии: Метод возвращает промис со входной декларацией. Никаких изменений декларации не производится.

getBuildSuffixes()

Аргументы: -

Возвращаемое значение: {Array} Суффиксы.

Описание: Позволяет настроить работу с суффиксами для команды bem build.

Используется: Если нужно, чтобы команды bem create и bem build работали с разными суффиксами. Например, когда из файлов технологии блоков с одним суффиксом должен собираться бандл технологии с другим.

Поведение в базовой технологии: Возвращает массив с одним элементом — суффиксом технологии, для которой производится сборка бандла технологии.

getBuildResult(prefixes, suffix, outputDir, outputName)

Аргументы:

  • {Array} prefixes — промис с массивом префиксов, для которых осуществляется сборка бандла
  • {String} suffix — суффикс бандла технологии
  • {String} outputDir — путь к каталогу, в котором создается бандл
  • {String} outputName — имя файла бандла без суффикса.

Возвращаемое значение: {String} промис с содержимым бандла технологии для текущего суффикса.

Описание: Метод отвечает за сборку содержимого бандла для текущего суффикса.

Используется: Когда нужно производить действия с содержимым бандла технологии. Например, изменить порядок включения фрагментов, полученных из исходных файлов, или поместить весь бандл технологии внутрь какой-нибудь конструкции. Например, HTML-код внутрь тегов <html> ... </html>.

Поведение в базовой технологии: На основании префиксов и суффикса метод создает массив путей собираемых файлов. Проверяет, существуют ли файлы из массива. Запускает для существующих файлов метод getBuildResultChunk(relPath, path, suffix), формирующий фрагмент содержимого бандла для текущего файла. Накапливает результаты выполнения метода getBuildResultChunk(relPath, path, suffix) в переменной res[suffix] и возвращает ее в виде промиса.

Пример: В качестве примера рассмотрим модуль технологии xml.js. Метод getBuildResult(prefixes, suffix, outputDir, outputName) переопределен в модуле таким образом, что отдельные фрагменты данных помещаются в конструкцию <fest:template xmlns:fest="http://fest.mail.ru"> ... </fest:template>, задающую пространство имен XML.

getBuildResult: function (prefixes, suffix, outputDir, outputName) {
        return Q.when(this.__base(prefixes, suffix, outputDir, outputName), function (chunks) {
            return Template.process([
                '<fest:template xmlns:fest="http://fest.mail.ru">',
                chunks.join('\n'),
                '    <fest:include src="' + outputName  + '.page.xml" />',
                '</fest:template>'
            ]);
        });
    },
getBuildResultChunk(relPath, path, suffix)

Аргументы:

  • {String} relPath — относительный путь к обрабатываемому файлу технологии
  • {String} path — абсолютный путь к обрабатываемому файлу технологии
  • {String} suffix — суффикс обрабатываемого файла технологии.

Возвращаемое значение: {String} – фрагмент данных, относящихся к обрабатываемому файлу.

Описание: Метод служит для формирования фрагмента данных, относящихся к одному исходному файлу.

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

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

Поведение в базовой технологии: Возвращает строку, содержащую относительный путь к обрабатываемому файлу.

Пример: Технология CSS из набора стандартных модулей использует этот метод для того, чтобы поместить путь к CSS-файлу в конструкцию @import url('...').

exports.techMixin = {

    getBuildResultChunk: function(relPath, path, suffix) {
        return '@import url(' + relPath + ');\n';
    } };

Общие методы команд bem create и bem build

getSuffixes()

Аргументы: -

Возвращаемое значение: {Array} Суффиксы.

Описание: Метод-хелпер. Позволяет настроить работу с суффиксами для команд bem create и bem build.

Используется: В простых случаях, если нужно, чтобы команды bem create и bem build работали с одним общим суффиксом.

Поведение в базовой технологии: В цепочке вызовов базовой технологии метод вызывается через getBuildSuffixes() и getCreateSuffixes(). Для getBuildSuffixes() возвращает массив суффиксов исходных файлов, участвующих в сборке. Для getCreateSuffixes() возвращает массив суффиксов создаваемых файлов.

Пример: Модуль технологии JS из набора стандартных модулей создает и собирает из блоков файлы с суффиксом js. Поэтому для работы с суффиксами модулю достаточно переопределить метод getSuffixes().

exports.techMixin = {

    getSuffixes: function() {
        return ['js'];
    }

};
getDependencies()

Аргументы: -

Возвращаемое значение: {Array} массив технологий, от которых зависит данная.

Описание: Метод-хелпер. Предоставляет список зависимостей в виде массива бандлов технологий, от которых зависит сборка данного бандла технологии. Используется bem make / server для построения графа зависимостей.

Используется: В случаях, когда собираемый бандл технологии зависит от другой технологии того же бандла.

Поведение в базовой технологии: Отсутствует в стандартной цепочке вызовов.

Пример: Для примера рассмотрим модуль технологии bemdecl.js из набора стандартных модулей технологии. Технология ищет файл имя_сущности.bemjson.js и преобразует его в имя_сущности.bemdecl.js. Для корректной работы модулю необходим бандл технологии bemjson.js.

exports.techMixin = {

    getDependencies: function() {
        return ['bemjson.js'];
    }

};

Приложения

Приложение 1. Перечень стандартных модулей технологий

bemdecl.js.js

Команда: bem create.

На входе: Файл имя_сущности.bemjson.js.

На выходе: Файлимя_сущности.bemdecl.js.

Описание: При запуске команды bem create модуль ищет файл имя_сущности.bemjson.js и преобразует его в имя_сущности.bemdecl.js. Файл bemjson.js – это декларация, описывающая структуру страницы (БЭМ-дерево). Файл bemdecl.js содержит набор уникальных БЭМ-сущностей в рамках собираемого бандла. Каждая сущность записывается в файл bemdecl.js в порядке их следования в bemjson.js.

blocks.js

Команда: bem create.

На входе: -

На выходе: Уровень переопределения имя_сущности.blocks/.

Описание: Модуль технологии служит хелпером для команды bem create level. Используется для создания уровня переопределения со ссылкой на прототип .bem/levels/blocks.js. При вызове команды bem create -b desktop -t blocks будет создан каталог уровня переопределения desktop.blocks.

bundles.js

Команда: bem create.

На входе: -

На выходе: Уровень переопределения имя_сущности.bundles/.

Описание: Работает аналогично blocks.js. Используется для создания уровня для бандлов со ссылкой на прототип .bem/levels/bundles.js. При вызове команды bem create -b desktop -t bundles будет создан каталог уровня переопределения desktop.bundles.

examples.js

Команда: bem create.

На входе: -

На выходе: Уровень переопределения имя_сущности.examples/.

Описание: Работает аналогично bundles.js. Используется для создания уровня для примеров со ссылкой на прототип .bem/levels/examples.js. При вызове команды bem create -b button -t examples будет создан каталог уровня переопределения button.examples.

project.js

Команда: bem create.

На входе: -

На выходе: Каталог проекта с набором подкаталогов.

Описание: Создает стартовую структуру проекта. В каталоге проекта модуль создает каталоги .bem, .bem/techs и .bem/levels. В каталоге .bem создается файл level.js со ссылкой на прототип bem/lib/levels/project.js. В каталоге .bem/levels модуль создает уровни переопределения blocks.js, bundles.js и examples.js.

level.js

Команда: bem create.

На входе: -

На выходе: Каталог уровня переопределения.

Описание: Создает уровень переопределения со стандартными настройками (без прототипа).

css.js

Команда: bem create / bem build.

На входе: .css-файлы блоков, декларация бандла.

На выходе: имя_сущности.css.

Описание: Для команды bem create создает CSS-файл с прописанным селектором класса, соответствующим создаваемой БЭМ-сущности и фигурными скобками с новой строки.

.блок__элемент_модификатор_значение
{
}

Для команды bem build создает результирующий CSS-файл с перечнем импортов CSS-файлов блоков вида @import url (путь/до/файла/БЭМ-сущности.css).

ie.css.js

Команда: bem create / bem build.

На входе: .ie.css-файлы блоков.

На выходе: имя_сущности.ie.css.

Описание: Модуль предназначен для создания и работы с таблицами стилей для различных версий Internet Explorer. Для команды bem create создает CSS-файл с прописанным селектором класса, соответствующим создаваемой БЭМ-сущности. Для команды bem build создает результирующий ie.css-файл с перечнем импортов ie.css-файлов блоков. В него, выше импортов ie.css-файлов блоков, включается импорт результирующего CSS-файла собираемого бандла.

ie6.css.js

Команда: bem create / bem build.

На входе: .ie6.css-файлы блоков.

На выходе: имя_сущности.ie6.css.

Описание: Расширяет функциональность модуля ie.css.js. Модуль действует аналогично ie.css.js, но импорты ie6.css помещаются ниже импортов ie.css и css.

ie7.css.js

Команда: bem create / bem build.

На входе: .ie7.css-файлы блоков.

На выходе: имя_сущности.ie7.css.

Описание: Расширяет функциональность модуля ie.css.js. Модуль действует аналогично ie.css.js, но импорты ie7.css помещаются ниже импортов ie.css и css.

ie8.css.js

Команда: bem create / bem build.

На входе: .ie8.css-файлы блоков.

На выходе: имя_сущности.ie8.css.

Описание: Расширяет функциональность модуля ie.css.js. Модуль действует аналогично ie.css.js, но импорты ie8.css помещаются ниже импортов ie.css и css.

ie9.css.js

Команда: bem create / bem build.

На входе: .ie9.css-файлы блоков.

На выходе: имя_сущности.ie9.css.

Описание: Действует идентично ie.css.js. Разница только в суффиксе создаваемых/обрабатываемых файлов.

less.js

Команда: bem create / bem build.

На входе: .less-файлы блоков.

На выходе: имя_сущности.less.

Описание: Расширяет функциональность модуля css.js. Модуль действует аналогично css.js, но для команды bem build конструкция импорта имеет вид @import url("путь/до/файла/имя_сущности.less").

sass.js

Команда: bem create / bem build.

На входе: .sass-файлы блоков.

На выходе: имя_сущности.sass.

Описание: Расширяет функциональность модуля css.js. Модуль действует аналогично css.js, но для команды bem build конструкция импорта имеет вид @import путь/до/файла/имя_сущности.sass.

styl.js

Команда: bem create / bem build.

На входе: .styl-файлы блоков.

На выходе: имя_сущности.styl.

Описание: Расширяет функциональность модуля css.js. Для команды bem build конструкция импорта имеет вид @import "путь/до/файла/имя.styl", а для команды bem create первая фигурная скобка создается в той же строке, что и селектор.

.блок__элемент_модификатор_значение {
}

deps.js.js

Команда: bem create / bem build.

На входе: .deps.js-файлы блоков.

На выходе: имя_сущности.deps.js.

Описание: Модуль предназначен для работы с зависимостями блока. Команда bem create создает шаблон с пустыми массивами mustDeps и shouldDeps.

({
    mustDeps: [],
    shouldDeps: []
})

При вызове команды bem build модуль считывает deps.js-файлы блоков, рекурсивно раскрывает записанные в них зависимости, сериализует полученные данные и записывает их в результирующий deps.js-файл бандла. При этом зависимости типа mustDeps помещаются перед той сущностью, которая от них зависит.

js.js

Команда: bem create / bem build.

На входе: .js-файлы блоков.

На выходе: имя_сущности.js.

Описание: Для команды bem create модуль работает идентично базовой технологии. При вызове командой bem build модуль технологии собирает содержимое всех JS-файлов проекта в результирующий JS-файл.

js-i.js

Команда: bem create / bem build.

На входе: .js-файлы блоков.

На выходе: имя_сущности.js.

Описание: Для команды bem create модуль работает идентично базовой технологии. Команда bem build собирает ссылки на JS-файлы блоков в результирующий JS-файл, для дальнейшей обработки программой borschik. Ссылки имеют вид /*borschik:include:путь/до/файла/имя_сущности.js*/;.

dir.js

Команда: bem create.

На входе: -

На выходе: имя_сущности.dir/.

Описание: Создает каталог. Перед использованием следует связать технологию с осмысленным именем в файле .bem/level.js, например:

exports.getTechs = function() {

    return {
        'data': 'dir'
    };

};

Приложение 2. Структура файла декларации команды bem build

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

Структурированный вид записи

exports.blocks = [{
    name: 'first-block',      // имя блока
    mods: [{                  // модификаторы блока
       name: 'mod1',          // имя модификатора блока
       vals: ['1', '2']       // значения модификатора блока
    }],
    elems: [{                 // элементы блока
        name: 'elem1',        // имя элемента блока
        mods: [{              // модификаторы элемента
            name: 'mod1',     // имя модификатора элемента
            vals: ['1', '2']  // значения модификатора элемента
        }]
    }]
}];

Плоский список

exports.deps = [
    {
        block: 'first-block',  // имя блока
        elem: 'elem1',         // имя элемента блока
        mod: 'mod2',           // имя модификатора элемента
        val: '1'               // значение модификатора элемента
    },
    {
        block: 'second-block', // имя блока
        mod: 'mod3',           // имя модификатора блока
        val: '2'               // значение модификатора блока
    }
];

Приложение 3. Базовая технология bem-tools

Базовая технология в bem-tools реализована в классе Tech в модуле bem/lib/tech.js. Все модули технологий расширяют этот класс и доопределяют его методы.

В ходе выполнения команд bem create и bem build поведение базовой технологии различно. Рассмотрим отдельно поведение базовой технологии для каждой из команд.

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

Базовая технология команды bem create

Команда bem create служит для создания БЭМ-сущностей.

На входе

Команде bem create могут передаваться следующие параметры:

Аргумент Описание Влияет на Тип Обязательный Аргумент точки входа
[-T .. -t .. -n ..] Параметры технологии: -T – только заданная технология, -t – заданная технология добавляется к стандартным. -n – исключает определенную технологию. Суффиксы создаваемых файлов и выбор модуля технологии. Массив Нет (будут созданы технологии по умолчанию) opts
-b Имя блока Префикс создаваемого файла. Строка Да item.block
-e Параметры БЭМ-сущности. Элементы блока. Префикс создаваемого файла. Строка Нет opts
-m Параметры БЭМ-сущности. Модификаторы блока или элемента. Префикс создаваемого файла Строка Нет opts
-v Параметры БЭМ-сущности. Значения модификаторов блока или элемента. Префикс создаваемого файла. Строка Нет opts
-l Уровень переопределения, на котором создается сущность. Префикс создаваемого файла. Строка Нет level
Схема действия базовой технологии

Схема вызовов методов базовой технологии для команды bem create

Подготовительный этап

На основании входных параметров команды bem create определяется массив создаваемых сущностей. Для каждого элемента из массива сущностей определяется массив технологий, в которых данная сущность должна быть реализована. Затем для каждой технологии из массива создается экземпляр объекта технологии, у которого вызывается метод createByDecl(item, level, opts).

Точка входа

На этом этапе начинает работать модуль технологии, в данном случае, базовой. Вызывается метод createByDecl(item, level, opts). Метод конструирует из входных параметров item и level префикс создаваемого файла. Далее, из данных, содержащихся в opts, создает vars — словарь, содержащий сведения о создаваемой БЭМ-сущности и префикс.

Основной этап

За процесс формирования и записи содержимого создаваемых файлов отвечает метод create(prefix, vars, force). Сначала содержимое создаваемых файлов формируется с помощью метода getCreateResults(prefix, vars), затем для его сохранения вызывается метод storeCreateResults(prefix, res, force).

NB Метод create(prefix, vars, force) может быть переопределен для изменения общей схемы действия команды.

Формирование содержимого

Метод getCreateResults(prefix, vars) формирует содержимое всех создаваемых файлов. Для этого он с помощью метода getCreateSuffixes() получает массив суффиксов. На основании префикса и суффикса, getCreateResults(prefix, vars) вычисляет полный путь к создаваемому файлу path. После чего для каждого элемента массива суффиксов вызывается метод getCreateResult(path, suffix, vars), который формирует содержимое для этого элемента.

МетодgetCreateResults возвращает промис с хешем, в ключах которого лежат суффиксы создаваемых файлов, а в значениях — содержимое этих файлов.

NB Метод может быть переопределен для изменения содержимого создаваемого файла технологии.

Сохранение содержимого

За сохранение данных из объекта res на диске отвечает метод storeCreateResults(prefix, res, force).

Метод последовательно обрабатывает все пары ключ:значение из объекта res. Для каждой пары вызывается метод storeCreateResult(path, suffix, res, force).

Метод storeCreateResult(path, suffix, res, force) проверяет, существует ли создаваемый файл по пути, содержащемся в аргументе path. Если файл не существует, вызывается метод save(path, res[suffix]), который создает файл в соответствии со значением аргумента path и записывает в него содержимое аргумента res для текущего суффикса.

Если же файл по указанному пути существует, то проверяется значение аргумента force. Аргумент force — это булева переменная, получаемая из входного параметра opts. При значении true файл будет перезаписан.

Базовая технология команды bem build с API v2

Команда bem build предназначена для сборки файлов технологии с уровней блоков в общий бандл технологии. Сборка производится на основании файла декларации и списка уровней переопределения, передаваемого пользователем.

При этом в сборку попадают блоки, описанные в файле декларации, и находящиеся на уровнях переопределения из списка.

На входе

Команде bem build может передаваться следующий набор параметров:

Аргумент Описание Тип Обязательный Аргумент точки входа
-d Путь к файлу декларации сборки. Объект Да decl
-t Имя технологии или полный путь к модулю технологии. Строка Нет
-b Имя создаваемого блока. Строка Да opts
-l Уровни переопределения, с которых собираются БЭМ-сущности. Перечисляются в той последовательности, в которой нужно подключать БЭМ-сущности с этих уровней. Массив Нет levels
-L Уровень переопределения, на котором создается блок (бандл) с результирующими файлами. Строка Нет output
-e Параметры БЭМ-сущности для файла бандла (используется с опцией -L). Элементы блока. Строка Нет opts/output
-m Параметры БЭМ-сущности для файла бандла (используется с опцией -L). Модификаторы блока или элемента. Строка Нет opts/output
-v Параметры БЭМ-сущности для файла бандла (используется с опцией -L). Значения модификаторов блока или элемента. Строка Нет opts/output
-o -n Альтернативный способ указания пути к файлу бандла и его имени. -o – каталог, -n – имя файла Строки Нет output
Схема действия базовой технологии

Схема вызовов методов базовой технологии для команды bem build с API v2

Точка входа

Для API v2 базовой технологии команды bem build точкой входа является метод buildByDecl(decl, levels, output, opts). Этому методу передается:

  • {Object} decl — декларация, по которой должна производиться сборка файлов технологии
  • {Array{}} levels — массив уровней переопределения, блоки которых участвуют в сборке
  • {String} output — префикс создаваемого бандла
  • {Object} opts— хеш опций, переданных команде bem build.

Он вызывает getBuildResults(decl, levels, output, opts), результатом работы которого является хеш. Ключи хеша — это суффиксы собираемых файлов технологий, а значение — массив строк результатов сборки. Например, для технологии i18n.js он может выглядеть так:

{
 'en.js': ['...', '...', ...],
 'ru.js': ['...', '...', '...', ...],
 'tr.js': ['...', '...', ...]
}

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

Преобразование декларации сборки

На начальном этапе buildByDecl вызывает вспомогательный метод transformBuildDecl(decl), которому передается декларация сборки.

Метод возвращает промис с декларацией. По умолчанию, декларация возвращается без изменений. Метод может быть использован, если нужно производить преобразования декларации сборки.

NB Метод встроен в цепочку вызовов как вспомогательный для удобства работы с декларацией.

Формирование результатов сборки

Чтобы построить хеш, метод getBuildResults получает список собираемых файлов, используя вспомогательный метод getBuildPaths(decl, levels). В список попадают файлы, которые:

  • во-первых, фактически существуют на уровнях переопределения и в блоках, из которых производится сборка.
  • во-вторых, имеют суффиксы, указанные в методе getBuildSuffixesMap(), экспортируемом модулем технологии.

Затем производится валидация сборки. Для этого проверяется значение opts.force. При значении true бандл принудительно пересобирается.

При других значениях вызывается метод validate. Метод проверяет наличие файла бандла для текущего суффикса. Если он существует и собран из того же списка файлов, который вернул метод getBuildPaths, файл бандла считается валидным и дальнейшая сборка прекращается.

В противном случае для каждого суффикса (для технологииi18n.js это en.js, ru.js и т.д) вызывается getBuildResult(files, suffix, output, opts). Ему передается список файлов, отфильтрованный по конкретному суффиксу.

Каждый путь файла обрабатывается методом getBuildResultChunk(relPath, path, suffix), который на выходе формирует строку с содержимым, относящимся к файлу, обрабатываемому методом.

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

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

Сохранение результатов сборки

За сохранение результатов сборки отвечает метод storeBuildResults(prefix, res). Ему передается хеш с результатами сборки. Для каждого суффикса из ключей хеша вызывается метод storeBuildResult(path, suffix, res). Он сохраняет значение из хеша в файл бандла с соответствующим суффиксом.

Базовая технология команды bem build с API v1

На данный момент разработка модулей технологии, расширяющих базовую технологию команды bem build с API v1, не рекомендуется. Этот раздел приводится в качестве справочной информации для тех, кто уже использует модули технологии с API v1.

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

На входе

Команде bem build может передаваться следующий набор параметров:

Аргумент Описание Тип Обязательный Аргумент точки входа
-d Путь к файлу декларации сборки. Объект Да decl
-t Имя технологии или полный путь к модулю технологии. Строка Нет
-b Имя создаваемого блока. Строка Да output
-l Уровни переопределения, с которых собираются БЭМ-сущности. Перечисляются в той последовательности, в которой нужно подключать БЭМ-сущности с этих уровней. Массив Нет levels
-L Уровень переопределения, на котором создается блок (бандл) с результирующими файлами. Строка Нет output
-e Параметры БЭМ-сущности для файла бандла (используется с опцией -L). Элементы блока. Строка Нет output
-m Параметры БЭМ-сущности для файла бандла (используется с опцией -L). Модификаторы блока или элемента. Строка Нет output
-v Параметры БЭМ-сущности для файла бандла (используется с опцией -L). Значения модификаторов блока или элемента. Строка Нет output
-o -n Альтернативный способ указания пути к файлу бандла и его имени. -o – каталог, -n – имя файла. Строки Нет output
Схема действия базовой технологии

Схема вызовов методов базовой технологии для команды bem build с API v1

Подготвительный этап

На подготовительном этапе происходит преобразование входных аргументов из БЭМ-терминов в формат, принимаемый методом build(prefixes, outputDir, outputName).

Точка входа

Работа базовой технологии bem build начинается с вызова метода buildByDecl(decl, levels, output). Этому методу передается:

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

На этом этапе из префикса бандла технолоии output конструируются переменные outputDir и outputName, содержащие имя создаваемого файла и каталог, в котором он создается.

Работа с декларацией сборки

Затем вызывается метод transformBuildDecl(decl), которому передается декларация сборки. Метод возвращает промис с декларацией. По умолчанию, декларация возвращается без изменений. Метод встроен в цепочку вызовов как вспомогательный для удобства работы с декларацией.

Формирование массива префиксов

На основании декларации decl, полученной от метода transformBuildDecl(decl), и массива уровней переопределения levels формируется массив префиксов собираемых файлов. В дальнейшем, на основании массива префиксов и массива суффиксов будут определены файлы, которые попадут в сборку.

Основной процесс сборки

За общий процесс формирования и записи содержимого результирующих файлов отвечает метод build(prefixes, outputDir, outputName).

Для этого сначала вызывается метод getBuildResults(prefixes, outputDir, outputName), а затем данные, полученные при его выполнении, передаются методу storeBuildResults(prefix, res), сохраняющему их в результирующий файл.

Формирование результатов сборки

Выполнение метода getBuildResults, отвечающего за формирование результатов сборки, происходит в три этапа.

На первом этапе выполняется метод getBuildSuffixes(), который возвращает массив суффиксов исходных файлов.

На втором этапе производится итерация по всем элементам массива суффиксов. Для каждого элемента массива вызывается метод getBuildResult(prefixes, suffix, outputDir, outputName). Метод возвращает промис с данными для записи в результирующий файл с текущим суффиксом.


NB Процесс формирования результатов сборки для суффикса:

  • Сначала на основании массива префиксов и текущего суффикса формируется массив путей paths. На этом этапе происходит проверка наличия файлов на диске. В массив путей попадают только существующие файлы.

  • Затем для каждого элемента массива paths вызывается метод getBuildResultChunk(relPath, path, suffix), который возвращает фрагмент содержимого для текущего файла. По умолчанию возвращается строка, содержащая путь к исходному файлу технологии.


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

Сохранение результатов сборки

За сохранение результатов сборки отвечает метод storeBuildResults(prefix, res). Ему передается хеш с результатами сборки. Для каждого суффикса из ключей хеша вызывается метод storeBuildResult(path, suffix, res). Он сохраняет значение из хеша в файл бандла с соответствующим суффиксом.

NB Сохранение производится безусловно. Если создаваемые файлы уже существуют на диске, они будут перезаписаны.

Приложение 4. Изменения сигнатур методов в базовом классе технологии API v2

v1 v2
buildByDecl(decl, levels, output) buildByDecl(decl, levels, output, opts)
getBuildResult(prefixes, suffix, outputDir, outputName) getBuildResult(files, suffix, output, opts)
getBuildResults(prefixes, outputDir, outputName) getBuildResults(decl, levels, output, opts)
getBuildPrefixes(decl, levels) :x:
build(prefixes, outputDir, outputName) :x:
filterPrefixes(prefixes, suffixes) :x:
:x: getBuildSuffixesMap()
:x: getBuildPaths(decl, levels)
:x: saveLastUsedData(file, data)
:x: getLastUsedData(file)
  • Аргумент opts во всех методах, где он встречается, представляет собой хеш параметров, переданных команде bem build. В него же можно добавлять свои вспомогательные параметры.
  • Вместо пары аргументов outputDir и outputName во все методы, где они использовались, передается один аргумент — output. Он содержит путь без суффикса к файлу (файлам) бандла технологии.
  • Вместо аргумента prefixes, содержащего пути к собираемым файлам технологий, которые могут находиться в блоках, методу getBuildResult(files, suffix, output, opts) передается аргумент files. Это массив файлов, которые фактически существуют по путям, с которых производится сборка и имеют суффиксы, соответствующие собираемой технологии. Элемент массива — это объект со свойствами:

    • file — имя файла
    • absPath — абсолютный путь к файлу
    • lastUpdated — дата модификации файла
    • suffix — суффикс файла.
  • Метод getBuildPaths() по переданной декларации decl и списку уровней переопределения levels возвращает список фактически существующих на диске файлов, участвующих в сборке. Список — это хеш, в котором файлы сгруппированы по суффиксу технологии. Например:

{
    css: [{...}, {...}, {...}],
    js: [{...}, {...}],
    bemhtml: [{...}, {...}, {...}, {...}]
}
  • Парные методыsaveLastUsedData(file, data)/getLastUsedData(file) позволяют сохранить/загрузить список файлов, из которых технология строила файл бандла file в последний раз. Метод getLastUsedData(file) может быть использован для валидации сборки. Он позволяет определить, нужно ли заново пересобирать файл бандла или же существующий валиден, так как был построен из тех же файлов, которые участвуют в текущей сборке.
Если вы заметили ошибку или хотите чем-то дополнить статью, вы всегда можете написать об этом, или поправить статью с помощью prose.io.