Toolkit to work with files based on BEM methodology.
You need NodeJS 0.10+ or later and npm 2.x+.
Run npm install bem
to install bem-tools
locally.
Get the list of commands with bem --help
.
To read about commands and subcommands use bem COMMAND --help
or bem COMMAND SUBCOMMAND --help
.
To make completions for bem-tools available in your bash, run following command (ensure that you have bash-completion installed, first). Run this
bem completion > /path/to/etc/bash_completion.d/bem
and restart bash.
If you aren't using bash-completion
, you can add bem completion
to your .bashrc
and reload:
bem completion >> ~/.bashrc
source ~/.bashrc
If you use zsh
, you can add bem completion
to your .zshrc
and reload:
bem completion >> ~/.zshrc
source ~/.zshrc
You can create following entities using bem create
:
- levels of defenition
- blocks
- elements
- modifiers
Level of defenition is a directory that holds blocks and an utility directiry .bem
.
A .bem
directory holds configuration of a current level:
- naming convention
- links to the technologies
An example of technologies' links (this is blocks-desktop
level of
bem-bl
block library):
https://github.com/bem/bem-bl/blob/master/blocks-common/.bem/level.js
bem create level blocks
In bem-tools
terms pages are blocks as well and a directory which holds pages is a level of
defenition itself. To create such a directory run this:
bem create level pages
bem create level
allows to use an existing level as a prototype for a level it creates.
bem create level --level bem-bl/blocks-desktop blocks
Block is a bunch of files in different technologies that hold block's implementation.
bem create block b-my-block
By default, a block has several techs: (bemhtml
, css
, js
).
Flags -t (-T) are to create files of technologies you need:
bem create block -t deps.js b-my-block
// Creates a block implementation in deps.js technology, ecxept of default techs.
bem create block -T css b-my-block
// Creates only CSS technology for a block
bem create block -T bem-bl/blocks-desktop/i-bem/bem/techs/bemhtml.js b-my-block
// -T flag is useful when you need to add a new tech to the block existed
The value of this flag may be either tech's name (e.g css
) or a path to tech module.
Tech names may be listed in .bem/level.js
file of a level.
E.g., https://github.com/bem/bem-bl/blob/master/blocks-common/.bem/level.js
You can find the examples of tech modules in the repo:
https://github.com/bem/bem-tools/tree/master/lib/techs
Create element named elem
for block b-my-block
bem create elem -b b-my-block elem
Create modifier named mod
for block b-my-block
bem create mod -b b-my-block mod
Create modifier named mod
having value val
for block b-my-block
bem create mod -b b-my-block mod -v val
Create modifier named mod
for element elem
of block b-my-block
bem create mod -b b-my-block -e elem mod
Create modifier named mod
having value val
for element elem
of block b-my-block
bem create mod -b b-my-block -e elem mod -v val
You can create any BEM entities or bunches of them using bem create
command.
Create blocks named b-block1
and b-block2
bem create -b b-block1 -b b-block2
Create elements named elem1
and elem2
for block b-block
bem create -b b-block -e elem1 -e elem2
Create modifier names mod
of block b-block
bem create -b b-block -m mod
Create modifier named mod
of block b-block
having values val1
and val2
bem create -b b-block -m mod -v val1 -v val2
Create modifier named mod
for element elem
of block b-block
bem create -b b-block -e elem -m mod
Create modifier named mod
having values val1
and val2
for element elem
of block b-block
bem create -b b-block -e elem -m mod -v val1 -v val2
bem build
command builds page files in different techs, according to a page declaration.
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
You can use either tech's name or a path to its module as a value of -t flag. This module says how to build a final file from a declaration.
E.g., this is a module for deps.js
: https://github.com/bem/bem-tools/blob/master/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
There is an example how pages are built using bem build
in our test project that uses
bem-bl
block library: https://github.com/toivonen/bem-bl-test/blob/master/GNUmakefile
bem decl
is to work with declaration files. Thus,
- to merge two or more decls into one
- «subtract» decls
All subcommands of bem decl
can take either bemdecl.js or deps.js as input declaration formats.
as input declaration (via -d
flag).
Ouput data (-o
flag) is always in deps.js
format.
bem decl merge
is to merge two or more decls into one. It is useful if you need, for example, to build
one file for several pages.
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
is to «subtract» all next decls from the first one.
You may use it to create a bundle that you request by application.
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
make
command implements the build process of the BEM projects. You don't have to write your own scripts or makefiles (for GNU make or other build system) to build your BEM project.
Since 0.10.0
bem make
also supports enb make
under the hood which is recomended way to build your projects.
During the build bem make
- fetches the block libraries
- builds the levels content
- builds the bundles
- generates the templates (
bemhtml
) - generates
html
frombemjson.js
- generates the static content files (
js
,css
) - expands the
@import
derectives incss
files (borschik
) - expands the
borschik:link:include
directives injs
files (borschik
) - optimizes
css
files usingcsso
- optimizes
js
files usinguglifyjs
bem server
command runs a development server. It makes the project files being accessible via the http protocol.
This includes the files which are generated during the build process. So the server can be useful when you develop the
static pages using the bem method. You just edit the files, refresh the browser and get updated page. All the files
which are affected by your changes will be rebuilt automatically.
In the case your project has no static pages you can configure your backend server and production environment to retrieve
the stylesheets and scripts from the bem server. bem server accepts connections via normal TCP socket and via UNIX domain socket.
By default the current directory is considered as the project root. You can change it using the --project (-r) option.
Default TCP port is 8080. You can change it using the --port (-p) option.
When requested URL is mapped to a directory, the server will check if there is an index.html file or it's possible to build it. In the case one of these is true the content of the file will be returned to browser. The directory content listing will be returned otherwise.
Since 0.10.0
bem server
also supports enb server
under the hood which is recomended way to build your projects.
Since 0.10.0
bem make
and bem server
also supports ENB
under the hood which is recomended way to build your projects. So for build configuration please refer ENB documentation.
The info about configuration bellow is deprecated and will be removed in the next version.
There is a default build behavior programmed in the build system. The configuration files allow to adjust it a little or change it completely.
To make bem make
work you should have .bem/level.js
file within your levels. It should contain the getTechs()
function,
which returns object with the tech definitions used on the level.
And it should have function getConfig()
:
var extend = require('bem/lib/util').extend;
exports.getTechs = function() {
return {
'bemjson.js': '',
'js': 'js-i',
'bemhtml.js': '../../bem-bl/blocks-common/i-bem/bem/techs/bemhtml.js',
'priv.js': '../../.bem/techs/priv.js',
'html': '../../bem-bl/blocks-common/i-bem/bem/techs/html'
};
};
exports.getConfig = function() {
return extend({}, this.__base() || {}, {
bundleBuildLevels: this.resolvePaths([
'../../bem-bl/blocks-common',
'../../bem-bl/blocks-desktop',
'../../blocks'
])
});
};
getTechs()
returns an object with used techs. Object properties (for example 'bemjson.js'
, 'js'
, 'bemhtml.js'
) define the
tech names, object values specify the paths to the appropriate tech files (''
, 'js-i'
, '../../bem-bl/blocks-common/i-bem/bem/techs/bemhtml.js'
).
A path can be relative or absolute, it can be empty, or it can specify just a file name. When the latter case is used the
tech will be considered being standard (bundled with bem-tools) and the file will be looked up in the [bem]/lib/techs
folder.
getConfig()
function returns an object with the bundleBuildLevels
property, containing the array of the used block levels.
Another (optional) configuration file is .bem/make.js
located in the project root. Core of the build system is a graph
of nodes, each of which executes own part of the whole build process. make.js
allows you to adjust nodes behavior and change build graph.
There are several standard node types:
Node
- base node, implements basic functionality. All other nodes are inherited from this oneLibraryNode
- retrieves external librariesLevelNode
- inspects the contents of a level and constructs graph branch accordingly to build the levelBundlesLevelNode
- inherits fromLevelNode
and builds the bundles levelsBundleNode
- constructs graph branch for a bundleMergedBundleNode
- builds merged bundle (aka common bundle)BorschikNode
- processes files with theborschik
utility,csso
anduglifyjs
Arch
- builds initial graph, which by default consists ofLibraryNode
,BundlesLevelNode
andLevelNode
nodes
To alter build system behavior for your project you need to alter behavior of the nodes. This can be achieved by adding MAKE.decl()
calls in the .bem/make
file. MAKE.decl()
is a helper
function which accepts two arguments. First one is the node name which we want to change, second - an object with overriding methods.
MAKE.decl('BundleNode', {
});
Node classes have some fundamental methods, which take care about the build process:
isValid()
- validates the node - indicates is there a need to rebuild it or not. If node artifacts were built during previous build and dependency nodes were not rebuilt after that, the node is considered being valid. In other words if you changed a file after first build then only the nodes which depend on this file will be rebuilt during the consequent build.make()
- implements the build logic for the node.run()
- node entry point. In the default implementation it executes isValid method and in case it returns false the make method will be executed next.clean()
- removes the build artifacts for the node.
Build of static html, css, js, bemhtml templates on the level pages
. Bemjson file is used as a source file. Also using blocks level blocks
, and also blocks-common
and blocks-desktop
from bem-bl.
pages/.bem/level.js
var extend = require('bem/lib/util').extend;
exports.getTechs = function() {
return {
'bemjson.js': '',
'bemdecl.js': 'bemdecl.js',
'deps.js': 'deps.js',
'js': 'js-i',
'css': 'css',
'bemhtml.js': '../../bem-bl/blocks-common/i-bem/bem/techs/bemhtml.js',
'html': '../../bem-bl/blocks-common/i-bem/bem/techs/html.js'
};
};
exports.getConfig = function() {
return extend({}, this.__base() || {}, {
bundleBuildLevels: this.resolvePaths([
'../../bem-bl/blocks-common',
'../../bem-bl/blocks-desktop',
'../../blocks'
])
});
};
.bem/make.js
MAKE.decl('Arch', {
getLibraries: function() {
return {
'bem-bl': {
type: 'git',
url: 'git://github.com/bem/bem-bl.git'
}
};
}
});
MAKE.decl('BundleNode', {
getTechs: function() {
return [
'bemjson.js',
'bemdecl.js',
'deps.js',
'bemhtml.js',
'css',
'js',
'html'
];
}
});
Build of css, js, bemhtml tamples on the level pages
. bemdecl
declaration file is used as a source file. Also using blocks level blocks
, and also blocks-common
and blocks-desktop
from bem-bl.
pages/.bem/level.js
var extend = require('bem/lib/util').extend;
exports.getTechs = function() {
return {
'bemdecl.js': 'bemdecl.js',
'deps.js': 'deps.js',
'js': 'js-i',
'css': 'css',
'bemhtml.js': '../../bem-bl/blocks-common/i-bem/bem/techs/bemhtml.js'
};
};
exports.getConfig = function() {
return extend({}, this.__base() || {}, {
bundleBuildLevels: this.resolvePaths([
'../../bem-bl/blocks-common',
'../../bem-bl/blocks-desktop',
'../../blocks'
])
});
};
.bem/make.js
MAKE.decl('Arch', {
getLibraries: function() {
return {
'bem-bl': {
type: 'git',
url: 'git://github.com/bem/bem-bl.git'
}
};
}
});
MAKE.decl('BundleNode', {
getTechs: function() {
return [
'bemdecl.js',
'deps.js',
'bemhtml.js',
'css',
'js'
];
}
});
The block libraries are not used by default. To use a library add the following code to .bem/make.js
:
MAKE.decl('Arch', {
getLibraries: function() {
return {
'bem-bl': {
type: 'git',
url: 'git://github.com/bem/bem-bl.git'
}
};
}
});
Where:
'Arch'
- node class name which we want to override. Arch builds initial build graph.getLibraries
- a method of the Arch class, which returns the associative array of the used block libraries.'bem-bl'
— the name of the library and the folder where it will be copied to.type
- the type of the library source. We use git in the example, so the library will be checked out of a git repository. Possible values are:'git'
,'svn'
,'symlink'
.svn
works the same asgit
, but with svn repositories.symlink
- creates a symbolic link in the project folder to the library folder. The library path is specified by therelative
property.url
- URL to the svn/git repository
Also you can use shorter code:
MAKE.decl('Arch', {
libraries: {
'bem-bl': {
type: 'git',
url: 'git://github.com/bem/bem-bl.git'
}
}
});
The folders in the project root matching the blocks*
mask are considered being the blocks level. You can change this using the following code:
MAKE.decl('Arch', {
blocksLevelsRegexp: /regular expression/,
});
The regular expression will be used to match the folders in the project root. A folder which does match will be used as the blocks level.
If you need some logic for the levels selection you can achieve that by overriding the createBlocksLevelsNodes()
method:
MAKE.decl('Arch', {
createBlocksLevelsNodes: function(parent, children) {
// Create the LevelNode instance
var node1 = new LevelNode(...);
// Add it into the graph
this.arch.setNode(node1, parent, children);
var node2 = new LevelNode(...);
this.arch.setNode(node2, parent, children);
// return an array with the Ids of the created nodes
return [node1.getId(), node2.getId()];
}
});
The folders in the project root matching the pages*
abd bundles*
masks are considered being bundle level. You can change this using the following code:
MAKE.decl('Arch', {
bundlesLevelsRegexp: /regular expression/,
});
And for more precise control:
MAKE.decl('Arch', {
getBundlesLevels: function() {
return [
'pages-desktop',
'pages-touch',
'bundles/common'
];
}
});
For every bundle the following target files are built by default:
.bemhtml.js
.html
.css
.ie.css
.js
_*.css
_*.ie.css
_*.js
and the intermediate:
.bemdecl.js
.deps.js
.deps.js.deps.js
.bemhtml.js.meta.js
.js.meta.js
.css.meta.js
.ie.css.meta.js
.bemjson.js
file is considered as a source file. If it does not exist, .bemdecl.js
is used then. If .bemdecl.js
does not exist too, .deps.js
will be used. For the cases when .bemjson.js
does not exist static html will not be built.
To change the list of the file techs to use, add the following code into .bem/make.js
:
MAKE.decl('BundleNode', {
getTechs: function() {
return [
'bemdecl.js',
'deps.js',
'bemhtml.js',
'css',
'js',
'priv.js'
];
}
});
IMPORTANT: Techs in the list should be in the order of dependency on each other. Tech B, which depends on A, should go bellow A. The source file tech should also be in the list, for example bemjson.js
.
The merged bundle — a bundle which includes the declarations of all bundles on the level. So for example css in a merged bundle will contain the styles from all of the bundles.
The following code will enable the build of the merged bundles for all levels:
MAKE.decl('BundlesLevelNode', {
buildMergedBundle: function() {
return true;
}
});
If you need a merged bundle for the selected levels only (for pages-desktop
level in the example):
var PATH = require('path');
MAKE.decl('BundlesLevelNode', {
buildMergedBundle: function() {
if (this.getLevelPath() === 'pages-desktop') return true;
return false;
}
});
The getLevelPath()
method returns the relative path for the level. We can use it to decide should we enable some special logic for current level or not.
To change the merged bundle name use the code:
MAKE.decl('BundlesLevelNode', {
mergedBundleName: function() {
return 'mymergedbundle';
}
});
By changing the YENV
environment variable value, you can switch between the production and development builds.
In production mode static files are processed with the borschik
utility. It expands the include directives and puts the
result content in the file with the _
prefix. For example, index.css
has the directives to include blocks/block1.css
and blocks/block2.css
. _index.css
will be created with the content of both block1.css
and block2.css
. Also the
css
files are optimized with the csso
utility, the js
files are optimized with uglifyjs
. In development mode
borschik
is used only, no optimizations take the place.
The default mode is development. To use the production mode set YENV
to production
.
Environment variables can be set in .bem/make.js
, for example
process.env.YENV = 'production';
A level should have .bem/level.js
configuration file which contains the meta information about the level:
- the mapping rules between the BEM entities and the file system
- the thech modules defined on the level
- the meta information for the build system
When the bem create level
command is used to create a level the empty .bem/level.js
file will be also created.
Which means that this level is «standard» one. The logic for standard level is defined in the Level
class within
(lib/level.js)[https://github.com/bem/bem-tools/blob/master/lib/level.js].
As the .bem/level.js
file is a CommonJS module it's easy to override the level's behavior. bem-tools
creates a new
class inherited from the standard Level
class using export of this module as a class extention (under the hood the
inherit module is used).
In the example bellow the getTechs()
method is overriden.
exports.getTechs = function() {
return {
'bemjson.js': ''
'css': 'path/to/my/css-tech-module.js'
}
};
To avoid the copy and paste of the same code among several levels you can put the common parts into the independant modules and inherit them. This way you can build up the levels hierarchy.
To specify the base level you should export it in the baseLevelPath
property. For example
exports.baseLevelPath = require.resolve('path/to/base/level.js');
It's also possible to create the inherited levels using the command
bem create level <your-level-name> --level path/to/base/level.js
By default the following mapping scheme is used (this example is about the css
tech):
level/
block/
__elem/
_mod/
block__elem_mod_val.css
block__elem.css
_mod/
block_mod_val.css
block.css
If you want to use a custom scheme override the appropriate match*()
and get*()
methods in the .bem/level.js
file.
To define a list of the tech modules used on the level export the getTechs()
function. It should return an object
the keys of which contain the tech names and the values contain on of the following:
- the absolute tech path;
- a short tech name — a tech module with such name bundled with
bem-tools
will be used; - an empty string — the default tech implementation will be used.
By deault there is no any techs defined explicitly on a level. In the case some techs are used within such a level
by a short name (for example css
, js
, etc) then the appropriate tech modules bundled with bem-tools
are loaded.
If such do exist of course. The full list of such techs can be found there lib/techs.
If you try to use a tech which was not defined explicitly and which is not bundled with bem-tools
- the default tech
will be used (see lib/tech/v1.js).
The techs defined on the level are used:
- by the
bem create
command - by the
bem build
command - by the file system introspection (see the
getLevelByIntrospection()
of theLevel
class) - during the project build with the
bem make
andbem build
commands
It's recommended to define explicitly the used techs.
To let the build system know which levels should be used to build one bundle or another set the bundleBuildLevels
property within an object returned by the getConfig()
function to an array of these levels.
exports.getConfig = function() {
return extend({}, this.__base() || {}, {
bundleBuildLevels: this.resolvePaths([
// your levels here
])
});
};
Look for the documentation in the source code lib/tech/v1.js.
There are many ways to write a tech module.
Whatever manner you choose you can refer to the tech object from methods using this
.
Any base method is available using this.__base(...)
call. Tech class can be referenced
using this.__class
. Thanks to inherit module
that helps us to organize inheritance here.
You only need to declare regular CommonJS module and export some of its
functions to redefine them. By default your tech will derive from base Tech
class
defined in module lib/tech/v1.js.
exports.getCreateResult = function(...) {
// your code goes here
};
You can also group all methods in techMixin
object. This is a recommended way.
exports.techMixin = {
getCreateResult: function(...) {
// your code goes here
}
};
Besides function, you can also export baseTechPath
variable to define an
absolute path to a tech module you are extending. Or you can
var BEM = require('bem');
exports.baseTechPath = BEM.require.resolve('./techs/css');
You can also derive from tech module by its name using baseTechName
variable.
Base class will be chosen in the context of level where tech module will be used.
exports.baseTechName = 'css';
In this example new tech will derive from css
tech declared on level in file
.bem/level.js
.
If you need a total control, you can create a module that exports
the whole Tech
class.
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
}
});
If you need to base your tech on an existing one written in a simple way use
getTechClass()
function to get its class. We recommend to use getTechClass()
function all the time to not depend on tech implementation.
var INHERIT = require('inherit'),
BEM = require('bem'),
BaseTech = BEM.getTechClass(require.resolve('path/to/tech/module'));
exports.Tech = INHERIT(BaseTech, {
// your overrides go here
});
Starting from 0.2.0 version it is possible to use bem-tools
from API.
bem
module exports the object of a command that has an api
property.
It is to use in this way:
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(', '));
});
The example above shows that you can use all the commands (including subcommands).
A command accepts two args:
- Object
opts
command options - Object
args
command arguments
It returns an object of Q.promise
type.
Commands to create BEM entities.
Creates a level of defenition.
- String
outputDir
a directory of output (current directory by default) - String
level
a «prototype» of the level - Boolean
force
key to force level's creating if it already exists
- Array
names
Namef of levels you are creating
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);
});
Creates BEM entities: blocks, elems, modifiers and their values.
- String
level
Level directory (current directory by default) - Array
block
Block name (required) - Array
elem
Element name - Array
mod
Modifier name - Array
val
Modifier value - Array
addTech
Add the techs listed - Array
forceTech
Use only the techs listed - Array
noTech
Exclude the techs listed - Boolean
force
Force creating BEM entities files (rewrite)
var Q = require('q'),
BEM = require('bem').api,
forceTechs = ['css'],
block = 'b-header',
elem = 'logo',
mods = ['lang'],
vals = ['ru', 'en'];
Q.when(BEM.create({ forceTechs: forceTechs, block: block, mod: mods, val: vals }), function() {
console.log('Create mod %s of block %s with vals %s', mods.join(', '), block, vals.join(', '));
});
Q.when(BEM.create({ forceTechs: forceTechs, block: block, elem: elem, mod: mods, val: vals }), function() {
console.log('Create mod %s of elem %s of block %s with vals %s', mods.join(', '), elem, block, vals.join(', '));
});
Creates a block.
- String
level
A directory of block's level. (Current directory by default) - Array
addTech
Add the techs listed - Array
forceTech
Use these techs only - Array
noTech
Exclude these techs - Boolean
force
Force files creating
- Array
names
List of block 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(', '));
});
Creating an element.
- String
level
A directory of level. (Current directory by default) - String
blockName
A name of element's block (required) - Array
addTech
Add the techs listed - Array
forceTech
Use only the techs listed - Array
noTech
Exclude the techs listed - Boolean
force
Force creating element's files (to rewrite them)
- Array
names
List of element 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);
});
Creating a modifier for a block or an element.
- String
level
Level directory (current directory by default) - String
blockName
Block name of this modifier (required) - String
elemName
Element name - Array
modVal
Modifier value - Array
addTech
Add the techs listed - Array
forceTech
Use only the techs listed - Array
noTech
Exclude the techs listed - Boolean
force
Force creating modifier files (rewrite)
- Array
names
List of modifier
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', mods.join(', '), block, vals.join(', '));
});
Q.when(BEM.create.mod({ forceTechs: forceTechs, blockName: block, elemName: elem, modVal: vals }, { names: mods }), function() {
console.log('Create mod %s of elem %s of block %s with vals %s', mods.join(', '), elem, block, vals.join(', '));
});
Build files from blocks.
- String
outputDir
An output directory (current directory by default) - String
outputName
A filename (its prefix) for output - Level
outputLevel
Output level for BEM entity to create - String
block
Block name - String
elem
Element name - String
mod
Modifier name - String
val
Modifier name - String
declaration
A filename of input declaration (required) - Array
level
List of levels to use - Array
tech
List of techs to build
You should use one of the following to specify output prefix:
outputName
to specify full path-prefixoutputDir
plusoutputName
to specify directory path and file prefix (they will be joined for you)outputLevel
plus properties describing BEM entity:block
,elem
,mod
andval
(path-prefix will be constructed for you using level file mapping scheme)
var Q = require('q'),
B = require('bem'),
BEM = B.api,
decl = 'page.deps.js',
outputDir = 'build',
outputName = 'page',
levels = ['blocks-common', 'blocks-desktop'],
techs = ['css', 'js'];
// use outputDir and outputName options
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);
}
);
// use outputLevel option
var level = B.createLevel('path/to/level'),
block = 'page';
Q.when(
BEM.build({
outputLevel: level,
block: block
}),
function() {
console.log('Finished build of techs %s for levels %s. Result in %s.* files.',
techs.join(', '), levels.join(', '), level.getRelByObj({ block: block }));
}
);
Commands to work with declarations.
Merging two or more declarations into one.
- String
output
A file for output result. By default output is in STDOUT - Array
declaration
List of filenames for declarations (required)
Subtracting the next declarations from the first one.
- String
output
A file for output result. By default output is in STDOUT - Array
declaration
List of filenames for declarations (required)
To verify that your changes do not break existing functionality we recommend to run autotests and check that all of them pass. You can do that by executing the following command in the root of the project:
mocha
You can check the level of the code coverage by tests using the command:
make test-cover
Then open coverage.html file in a browser. Code lines which have not been executed during the tests run will be marked red.