Работа с файлами, написанными по БЭМ-методу.
Вам потребуется 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.js
bem 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 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 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 index
bem 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.js
bem 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.js
bem 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
имя файла декларации использования (обязательный параметр)