Работа с файлами, написанными по БЭМ-методу.
Вам потребуется NodeJS 0.4.x или выше и npm 1.x.
После этого достаточно npm -g install bem.
-
Установить nodejs
https://github.com/joyent/node/wiki/Installation
-
Установить npm
curl http://npmjs.org/install.sh | sudo sh
-
После установки сконфигурируйте
NODE_PATH:echo 'export NODE_PATH="'$(npm root -g)'"'>> ~/.bashrc && . ~/.bashrc
или
echo 'export NODE_PATH="'$(npm root -g)'"'>> ~/.zshrc && . ~/.zshrc
-
Установить bem-tools
sudo npm -g install bem
-
Для установки самой последней версии bem-tools воспользуйтесь командой
sudo npm -g install bem@unstable
Если вы планируете использовать bem вместе с библиотекой блоков
bem-bl, установите так же
xjst и ometajs.
sudo npm -g install xjst ometajsВсю информацию о параметрах использования можно получить с помощью bem --help.
Для информации о конкретной команде и подкомманде: bem COMMAND --help и bem COMMAND SUBCOMMAND --help.
Если вы используете bash и у вас установлен пакет bash-completion, выполните следующую команду и перелогиньтесь:
bem completion > /path/to/etc/bash_completion.d/bemЕсли вы не используете bash-completion, можете добавить вывод bem completion себе в .bashrc:
bem completion >> ~/.bashrcЕсли вы используете zsh, можете добавить вывод bem completion себе в .zshrc, после чего перелогиньтесь:
bem completion >> ~/.zshrcС помошью bem create можно создавать сущности:
- уровни переопределения
- блоки
- элементы
- модификаторы
Уровень переопределения -- это директория, в которой хранятся реализации
блоков и служебная директория .bem.
В .bem хранятся настройки этого уровня переопределения:
- соглашения об именовании
- ссылки на модули технологий
Пример настройки ссылок на модули технологий (уровень blocks-desktop библиотеки блоков bem-bl):
https://github.com/bem/bem-bl/blob/master/blocks-desktop/.bem/level.jsbem create level blocksВ терминах bem-tools страницы тоже блоки, директория со страницами
является уровнем переопределения. Создать такую директорию можно так:
bem create level pagesКоманда bem create level позволяет использовать существующий уровень переопределения
в качестве прототипа для создаваемого уровня.
bem create level -l bem-bl/blocks-desktop blocksБлок -- это директория с файлами реализаций в различных технологиях.
bem create block b-my-blockПо умолчанию блок создаётся с набором файлов для всех технологий по-умолчанию (bemhtml, css, js).
Использование флагов -t (-T) позволяет создавать файлы блока нужных технологий:
bem create block -t deps.js b-my-block
// Создаст реализацию в технологии deps.js помимо дефолтных
bem create block -T css b-my-block
// Создаст только технологию CSS для блока
bem create block -T bem-bl/blocks-desktop/i-bem/bem/techs/bemhtml.js b-my-block
// Флаг -T удобно использовать, если нужно добавить новую технологию для уже существующего блокаВ качестве значения флага может быть указано название технологии (например, css)
или путь до модуля технологии.
Названия технологий могут быть указаны в файле .bem/level.js уровня переопределения.
Например, https://github.com/bem/bem-bl/blob/master/blocks-desktop/.bem/level.js
Примеры реализации модулей технологий можно увидеть в репозитории:
https://github.com/bem/bem-tools/tree/nodejs/lib/techsС помощью команды bem build можно собирать файлы страниц для различных технологий,
основываясь на декларации страницы.
bem build \
-l bem-bl/blocks-common -l bem-bl/blocks-desktop \
-l blocks -l pages/index/blocks \
-d pages/index/index.bemjson.js -t bemdecl.js \
-o pages/index -n indexЗначением флага -t может быть как название технологии, так и полный путь до модуля технологии. В этом модуле указано, как именно по декларации собирается конечный файл.
Например, модуль для deps.js: https://github.com/bem/bem-tools/blob/nodejs/lib/techs/deps.js.js
bem build \
-l bem-bl/blocks-common -l bem-bl/blocks-desktop \
-l blocks -l pages/index/blocks \
-d pages/index/index.bemdecl.js -t deps.js \
-o pages/index -n indexbem build \
-l bem-bl/blocks-common -l bem-bl/blocks-desktop \
-l blocks -l pages/index/blocks \
-d pages/index/index.deps.js -t css \
-o pages/index -n index
bem build \
-l bem-bl/blocks-common -l bem-bl/blocks-desktop \
-l blocks -l pages/index/blocks \
-d pages/index/index.deps.js -t js \
-o pages/index -n indexbem build \
-l bem-bl/blocks-common -l bem-bl/blocks-desktop \
-l blocks -l pages/index/blocks \
-d pages/index/index.bemhtml.js \
-t bem-bl/blocks-desktop/i-bem/bem/techs/bemhtml.js \
-o pages/index -n indexПример построения страниц при помощи bem build есть в демонстрационном
проекте на блоках bem-bl: https://github.com/toivonen/bem-bl-test/blob/master/GNUmakefile
bem decl позволяет работать с файлами деклараций, а именно:
- объединять несколько деклараций в одну
- «вычитать» декларации, то есть получать разницу между ними
Для всех подкоманд bem decl в качестве входных деклараций (ключ -d) могут выступать
файлы как в формате bemdecl.json, так и файлы в формате deps.js.
На выходе (ключ -o) всегда получается файл в формате deps.js.
bem decl merge объединяет несколько деклараций в одну. Она бывает полезна в ситуациях,
когда, например, вам нужно собрать общую сборку для нескольких страниц.
bem decl merge \
-d pages/index/index.deps.js \
-d pages/about/about.deps.js \
-d pages/search/search.deps.js \
-o pages/common/common.deps.jsbem decl subtract «вычитает» из первой указанной декларации все остальные. Она полезна
в ситуациях, когда, например, вам нужно сделать бандл, которые будет догружатся на страницу
по требованию.
bem decl subtract \
-d bundles/heavy-block/heavy-block.deps.js \
-d pages/common/common.deps.js \
-o bundles/heavy-block/heavy-block.bundle.jsbem server запускает веб сервер разработчика, который делает доступными по http протоколу статические файлы,
динамичесие html страницы, получаемые из BEMJSON и BEMHTML файлов на лету, а так же пропускает через borschik css и js
файлы.
По умолчанию корневым каталогом веб сервера считается текущая директория. Вы можете указать нужный каталог с помощью ключа --project (-r). Таким образом, если в корне есть файл pages/about/main.css, то он будет доступен из браузера по адресу http://localhost:8080/pages/about/main.css.
TCP порт по умолчанию, который слушает сервер - 8080. Вы можете указать другой порт, используя ключ --port (-p).
Если сервер получит запрос на файл типа .html, то он вернет браузеру результат применения BEMHTML файла (.bemhtml.js) к BEMJSON файлу (*.bemjson.js) если они существуют. В противном случае сервер вернет содержимое самого *.html.
Когда запрашиваемый URL соответствует директории, сервер проверит есть ли в ней index.html или index.bemhtml.js и index.bemjson.js и вернет html или результат работы шаблона. Если файлов нет, браузер получит листинг файлов в директории.
Смотрите документацию в исходном файле lib/tech.js.
Существует три способа написания модулей технологии: очень простой, простой и для продвинутых.
Во всех описанных ниже способах из методов можно обратиться к объекту технологии через this,
а через this.__base(...) можно вызвать метод одного из базовых классов. Это является следствием
использование модуля inherit для органиазации
наследования.
Способ заключается в том, что вы создаёте обычный CommonJS модуль, из
которого экспортируете несколько функций, которые перекроют методы базового
класса Tech из модуля lib/tech.js.
В простом способе к экспортируемым функциям добавляется переменная baseTechPath, в которой
содержится абсолютный путь до расширяемого модуля технологии. По умолчанию расширяется базовый
класс Tech.
Например:
exports.baseTechPath = require.resolve('bem/lib/techs/css');Если вам нужен полный контроль, вы можете создать модуль, экспортирующий готовый класс технологии Tech.
var INHERIT = require('inherit'),
BaseTech = require('bem/lib/tech').Tech;
exports.Tech = INHERIT(BaseTech, {
create: function(prefix, vars, force) {
// do some creation work
},
build: function(prefixes, outputDir, outputName) {
// organize own build process
}
});Если в качестве базовой технологии вы хотите использовать одну из существующих технологий,
написанных в простом стиле, воспользуйтесь функцией getTechClass() модуля bem/lib/tech
для получения класса этой технологии.
var INHERIT = require('inherit'),
getTechClass = require('bem/lib/tech').getTechClass,
BaseTech = getTechClass(require.resolve('path/to/tech/module'));
exports.Tech = INHERIT(BaseTech, {
// your overrides go here
});В версии 0.2.0 появилась возможность использовать команды bem-tools через API.
Модуль bem экспортирует объект основной команды, у которого есть свойство api.
Использовать его можно так:
var Q = require('q'),
BEM = require('bem').api,
techs = ['css', 'js'],
blocks = ['b-block1', 'b-block2'];
Q.when(BEM.create.block({ forceTech: techs }, { names: blocks }), function() {
console.log('Create blocks: %s', blocks.join(', '));
});Как видно из примера, можно обращаться ко всем командам bem-tools, в том числе вложенным.
Команды принимают два аргумента:
- Object
optsопции команды - Object
argsаргументы команды
Возвращают объект типа Q.promise.
Команды для создания БЭМ-сущностей.
Создание уровня переопределения.
- String
outputDirдиректория для записи результата, по умолчанию текущая - String
level«прототип» уровня переопределения - Boolean
forceпринудительно создать уровень, даже если он существует
- Array
namesимена создаваемых уровней переопределения
var PATH = require('path'),
Q = require('q'),
BEM = require('bem').api,
outputDir = PATH.join(__dirname, 'levels'),
levels = ['blocks-common', 'blocks-desktop'];
Q.when(BEM.create.level({ outputDir: outputDir }, { names: levels }), function() {
console.log('Create levels %s at %s', levels.join(', '), outputDir);
});Создание блока.
- String
levelDirдиректория уровня переопределения, по умолчанию текущая - Array
addTechдобавить перечисленные технологии к технологиям для уровня по умолчанию - Array
forceTechиспользовать только указанные технологии - Array
noTechисключить указанные технологии из использования - Boolean
forceпринудительно создавать файлы блока
- Array
namesимена создаваемых блоков
var Q = require('q'),
BEM = require('bem').api,
addTechs = ['bemhtml'],
blocks = ['b-header'];
Q.when(BEM.create.block({ addTech: addTechs }, { names: blocks }), function() {
console.log('Create blocks: %s', blocks.join(', '));
});Создание элемента.
- String
levelDirдиректория уровня переопределения, по умолчанию текущая - String
blockNameимя блока (обязательный параметр) - Array
addTechдобавить перечисленные технологии к технологиям для уровня по умолчанию - Array
forceTechиспользовать только указанные технологии - Array
noTechисключить указанные технологии из использования - Boolean
forceпринудительно создавать файлы элемента
- Array
namesимена создаваемых элементов
var Q = require('q'),
BEM = require('bem').api,
addTechs = ['bemhtml', 'title.txt'],
block = 'b-header',
elems = ['logo'];
Q.when(BEM.create.elem({ addTech: addTechs, blockName: block }, { names: elems }), function() {
console.log('Create elems %s of block %s', elems.join(', '), block);
});Создание модификатора блока или иодификатора элемента.
- String
levelDirдиректория уровня переопределения, по умолчанию текущая - String
blockNameимя блока (обязательный параметр) - String
elemNameимя элемента - Array
modValзначения модификатора - Array
addTechдобавить перечисленные технологии к технологиям для уровня по умолчанию - Array
forceTechиспользовать только указанные технологии - Array
noTechисключить указанные технологии из использования - Boolean
forceпринудительно создавать файлы модификатора
- Array
namesимена создаваемых модификаторов
var Q = require('q'),
BEM = require('bem').api,
forceTechs = ['css'],
block = 'b-header',
elem = 'logo',
mods = ['lang'],
vals = ['ru', 'en'];
Q.when(BEM.create.mod({ forceTechs: forceTechs, blockName: block, modVal: vals }, { names: mods }), function() {
console.log('Create mod %s of block %s with vals %s', elems.join(', '), block, vals.join(', '));
});
Q.when(BEM.create.mod({ forceTechs: forceTechs, blockName: block, elemName: elem, modVal: vals }, { names: elems }), function() {
console.log('Create mod %s of elem %s of block %s with vals %s', elems.join(', '), elem, block, vals.join(', '));
});Сборка файлов.
- String
outputDirдиректория для записи результата, по умолчанию текущая - String
outputNameимя (префикс имени файла) для записи результата - String
declarationимя файла декларации использования (обязательный параметр) - Array
levelуровень переопределения - Array
techсобирать файлы указанных технологий
var Q = require('q'),
BEM = require('bem').api,
decl = 'page.deps.js',
outputDir = 'build',
outputName = 'page',
levels = ['blocks-common', 'blocks-desktop'],
techs = ['css', 'js'];
Q.when(
BEM.build({
outputDir: outputDir,
outputName: outputName,
declaration: decl,
level: levels,
tech: techs
}),
function() {
console.log('Finished build of techs %s for levels %s. Result in %s/%s.* files.',
techs.join(', '), levels.join(', '), outputDir, outputName);
}
);Команды для работы с декларациями использования.
Объединение деклараций.
- String
outputфайл для записи результата, по умолчанию STDOUT - Array
declarationимя файла декларации использования (обязательный параметр)
Вычитание деклараций.
- String
outputфайл для записи результата, по умолчанию STDOUT - Array
declarationимя файла декларации использования (обязательный параметр)