Войти с помощью github

Есть ли возможность примиксовать компоненту с определенными модификаторами поведение элемента какого-либо блока с его собственными модификаторами? К примеру:

Использовать подобный BEMJSON

{
    block: 'promo',
    content: [
        {
            block: 'button',
            mods: { type: 'link' },
            mix: { block: 'promo', elem: 'action' },
            elemMods: { type: 'secondary' },
            text: 'Secondary action',
            url: ''
        }
    ]
}

Примечание: понимаю, что использование elemMods здесь при определенных обстоятельствах (несколько миксов) приводит к неоднозначности, однако, насколько мне известно, сделать так: mix: [ { block: 'promo', elem: 'action', type: 'secondary' } ] не выйдет.

Как быть, чтобы получить примерно следующее?

<a class="button action_type_secondary promo__action">
    <span class="button__text">Secondary action</span>
</a>
  1. Допустим есть 10-20 страниц верстки. Шапка и подвал на этих 20 страницах повторяются 1 в 1. Хочешь что-то изменить? - 20 copy&paste в bemson. Это мой текущий уровень понимания. А нет ли случаем возможности выносить повторяющиеся части страниц в отдельные bemjson-файлы, чтобы править в одном месте? Я попробовал require в bemjson - работает, но не до конца. При повторной сборке bemjson-to-bemdecl сборщик (не зная про инклуды) считает что bemjson не изменился и естественно не перегенерирует bemdecl. Кто как решает эту DRY-задачку?
  2. Нет ли какой-нибудь технологии, которая на основе bemjson+bh сформирует список зависимостей как это сделано при сборке bemjson->bemdecl->deps? Очень надоедает для каждой bh-реализации руками писать deps.js

У нас есть документация про технологии БЭМ платформы (BEMJSON, BEMTREE, BEMHTML, DEPS), но практически нет туториалов по использованию их всех вместе. Есть несколько исключений, но они достаточно объемные и сложноваты для восприятия.

Я написал простой пример, рассчитанный на тех, кто уже немного освоился с версткой на основе project-stub и хочет продолжить свое знакомство с платформой.

Пусть у нас есть следующий файл с данными data.json:

{
    "user": "mathetes",
    "company": "WebExcel",
    "city": "Novosibirsk"
};

Как вариант, данные могут приходить из БД или через HTTP API — источник не играет роли.

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

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

В результате должен получиться следующий BEMJSON:

{
    block: 'page',
    content: [
        {
            block: 'header',
            content: {
                block: 'logo'
            }
        },
        {
            block: 'main',
            content: {
                block: 'user',
                content: 'тут-содержимое-карточки-пользователя'
            }
        },
        {
            block: 'footer',
            content: '© 2015 SuperPuper'
        }
    ]
}

BEMTREE-шаблон для блока page должен построить шапку, основную часть и подвал:

block('page').content()(function() {
    return [
        { block: 'header' },
        { block: 'main' },
        { block: 'footer' }
    ];
]);

По техзаданию в шапке должен быть логотип. Тогда шаблон шапки может выглядеть так:

block('header').content()(function(){
    return { block: 'logo' };
});

В основной части нужна карточка пользователя. Так что нам потребуется доступ к данным из файла data.json. Но пока отложим этот момент и захардкодим какие-то тестовые данные:

block('main').content()(function() {
    return {
        block: 'user',
        content: [
            {
                elem: 'name',
                content: 'test name'
            },
            {
                elem: 'company',
                content: 'test company'
            },
            {
                elem: 'city',
                content: 'test city'
            }
        ]
    };
});

В подвале нужен копирайт:

block('footer').content()('© 2015 SuperPuper');

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

В самом простом случае мы можем сохранить все шаблоны в один файл, установить пакет bem-xjst и с его помощью скомпилировать бандл:

bem-xjst -i path/to/templates.js -o bundle.bemtree.js

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

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

Получить декларацию с перечислением всех нужных блоков можно двумя способами: в *.bemdecl.js перечислить все нужные блоки (и не забывать добавлять и удалять их по мере разработки и рефакторинга), либо указать только корневой блок (в нашем случае page), а блоки, которые нужны корневому и всем последующим, указывать в их собственных списках зависимостей — deps.js. Второй путь гораздо гибче: сохраняется прицип БЭМ-методологии о том, что блок сам знает о себе всё, при удалении блока автоматически будут удалены и его зависимости, а при добавлении они автоматически включатся в сборку.

Так как шаблон блока page создает блоки header, main и footer, мы явно укажем это в списке зависимостей в файле page.deps.js:

({
    shouldDeps: ['header', 'main', 'footer']
})

Если вы имели опыт работы с project-stub, где нужные файлы попадали в сборку автоматически, то необходимость указывать зависимости вручную может показаться странной. Дело в том, что там у нас на руках заранее был готовый BEMJSON-файл, по которому можно было получить список всех необходимых сущностей. А в данном случае мы планируем генерировать BEMJSON в процессе сборки на основе шаблонов. При этом шаблоны необходимо собрать заранее, а значит декларацию нужных блоков потребуется описать самостоятельно.

Отлично, теперь мы знаем как собрать шаблоны. Следующим шагом необходимо получить с их помощью BEMJSON на основе данных, а затем из BEMJSON сгенерировать HTML с помощью BEMHTML. В общем виде это выглядит так:

var data = require('path/to/data.json'),
    BEMTREE = require('path/to/bundle.bemtree.js').BEMTREE,
    BEMHTML = require('path/to/bundle.bemhtml.js').BEMHTML,
    bemjson = BEMTREE.apply(data),
    html = BEMHTML.apply(bemjson);

require('fs').writeFileSync('index.html', html);

Эти преобразования будут работать и в браузере, если подключить bundle.bemtree.js и bundle.bemhtml.js на страницу. Останется только вставить полученную HTML-строку в DOM.

Осталось разобраться, как все-таки сгенерировать карточку пользователя на основе данных из data.json, вместо использования хардкода.

Как видно в примере кода выше, данные мы передаем в вызов BEMTREE.apply(data). При этом мы помним, что корневым блоком должен оказаться блок page. Достичь этого можно следующим образом:

var data = require('path/to/data.json');
BEMTREE.apply({
    block: 'page',
    data: data // теперь данные попадут в контекст шаблона блока page
});

Модифицируем код шаблона так, чтобы пробросить данные для вложенных в page блоков:

block('page').content()(function() {
    this.data = this.ctx.data; // this будет общим для всех потомков page,
                               // так что они смогут использовать поле data

    return [
        { block: 'header' },
        { block: 'main' },
        { block: 'footer' }
    ];
]);

Тогда финальный вид BEMTREE-шаблона блока main окажется таким:

block('main').content()(function() {
    var data = this.data;

    return {
        block: 'user',
        content: [
            {
                elem: 'name',
                content: data.user
            },
            {
                elem: 'company',
                content: data.company
            },
            {
                elem: 'city',
                content: data.city
            }
        ]
    };
});

Из соображений унификации в качестве корневого блока удобно использовать блок root, который будет отвечать за пробрасывание данных вглубь дерева и создавать page:

block('root').replace()(function() {
    return {
        block: 'page',
        title: 'TODO',
        head: [
            { elem: 'css', url: 'index.min.css' }
        ],
        scripts: [
            { elem: 'js', url: 'index.min.js' }
        ],
        mods: { theme: 'islands' }
    };
});

Попробовать описанный выше подход можно на основе репозитория-заготовки.

С недавнего времени я погружаюсь в БЭМ. И чтоб удостовериться в правильном ли я направлении двигаюсь, хочу попросить более опытных в этом деле ребят сделать небольшое ревью.

В качестве примера для верстки я взял одно старое Яндексовое тестовое задание - https://yandex.ru/jobs/vacancies/dev/dev_des/

Моя реализация - https://github.com/koloskof/bem-taxi

Буду благодарен!

подскажите пожалуйста в чем ошибка

код:

    var bemtreeTemplate = fs.readFileSync(path.join('.',pathToBundle, 'index.bemtree.js'), 'utf-8');
    var context = vm.createContext({
        console: console,
        require: require,
        Vow: vow
    });
    vm.runInContext(bemtreeTemplate, context);

ошибка:

node ./desktop.bundles/index/index.node.js
evalmachine.<anonymous>:85
       if('onreadystatechange' in doc.createElement('script')) { // ie6-ie8
                                      ^

TypeError: Cannot read property 'createElement' of undefined
    at evalmachine.<anonymous>:85:39
    at evalmachine.<anonymous>:104:7
    at Object.__vow_init (evalmachine.<anonymous>:1331:3)
    at buildBemXjst (evalmachine.<anonymous>:1335:12)
    at evalmachine.<anonymous>:1603:25
    at evalmachine.<anonymous>:1605:3
    at Object.exports.runInContext (vm.js:44:17)
    at /home/rustam/work/newkent/desktop.blocks/server/server.node.js:18:5
    at pendingRequires.push.cb (/home/rustam/work/newkent/desktop.bundles/index/index.node.js:88:32)
    at onDeclResolved (/home/rustam/work/newkent/desktop.bundles/index/index.node.js:175:29)

Добрый день! Извините за дилетантский вопрос. Подскажите, пожалуйста (или подскажите, где посмотреть), как вывести повторяющиеся элементы блока (см. код).

Необходимо в блоке вывести один раз title и три раза пару элементов year и university.

На странице должно быть так:

ОБРАЗОВАНИЕ 2000 - институт 1999 - институт 1998 - институт

Если добавить элементы, например, так:

sections: [
    {
        title: 'ОБРАЗОВАНИЕ',
        year: '2000 — ',
        university: 'институт',
        year: '1999 — ',
        university: 'институт',
        year: '1998 — ',
        university: 'институт'  
    }
]

выводится только последняя пара year и university.

index.bemjson.js:

//...
content: [
        { block : 'name',
          content : 'имя'
           },

        {
            block: 'sections',
            sections: [
                {
                    title: 'ОБРАЗОВАНИЕ',
                    year: '2000 — ',
                    university: 'институт'
                }
            ]
        }
        ]
//...

sections.bemhtml:

block('sections')(

    tag()('div'),

    content()(function() {
        return this.ctx.sections.map(function(item){
            return [
                {
                    elem: 'item',
                    content: [
                        {
                            elem: 'title',
                            content: item.title
                        },
                        {
                            elem: 'year',
                            content: item.year
                        },
                        {
                            elem: 'university',
                            content: item.university
                        }
                    ]
                },
                ' '
            ];

        });

    }),


    elem('item')(
        tag()('div')
    ),

    elem('title')(
        tag()('h3')
    ),

    elem('year')(
        tag()('span')
    ),

    elem('university')(
        tag()('span')
    )
);

Сделал свою первую небольшую страницу на основе generator-bem-stub блоки описывал в bemjson и прописывал правила css в common-blocks. Страница задумывалась как адаптивная. Поэтому нужно сделать для планшетов и телефонов. В папках touch-pad.bundles и touch-phone.bundles имеются bemjson с минимальным контентом.

Я так понимаю нужно скопировать содержимое desktop.bundles в папки touch-pad.bundles и touch-phone.bundles и прописать нужные css для них. Или как то по другому надо делать?

Если используется централизованное получение данных с бекенда, в чем преимущества использования bemtree по сравнению с прямым формированием полного дерева bemjson бекендом?

Нужно детальное описание для синтаксиса БЭМ. С блоками немного разобрался. Работают. Синтаксис в bemjson такой например:

 {
        block: 'slider',
        content: [
            {
                elem : 'slider__item',
                content : 'blocks'
            },
        ]
    },

В папку slider поместил папку с названием slider__item в нее поместил файл slider__item.сss, но стили не работают. Как вообще правильно. Помещать css элемента в файл css блока или создавать для него отдельный файл?

Здравствуйте!

Возможно ли изменение параметров блока в js-реализации другого?

К примеру, есть блок list с элементами item. У каждого элемента есть параметры id и name.

{
    block : 'list',
    elem : 'item',
    content : name,
    js : {
        id : id,
        name : name,
    }
}```

При клике на `item` я подгружаю соответствующий контент в основной блок на странице.
Меняю там название `name`, сохраняю на сервере, так же хотелось бы обновить элемент списка `list`.
Как мне найти нужный элемент списка, как изменить его параметры?

В приложении типа чат есть два списка: список общих комнат и список приватных бесед. Реализовал их блоком list с соответствующим модификатором type.

Задача: реализовать выбор одного элемента из списка. Проблема: каждый инстанс блока list запоминает свой активный элемент списка.

// При клике на элемент списка ставлю соответствующий модификатор
_onItemClick : function (e) {
    var item = $(e.currentTarget);
    var type = this.getMod(item, 'type');

    this.setMod(item, 'current', true);
}

// При выставлении модификатора новому элементу, удаляю модификатор у предыдущего
onElemSetMod : {
    'item' : {
        'current' : {
            'true' : function (elem) {
                this.delMod(this._current, 'current');
                this._current = elem;
            }
        }
    }
}

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

Так же интересует насколько правильной является реализация "оборачивания" всех элементов списка в контейнер с помощью создания нового элемента container

// BEMJSON
{
    block: 'list',
    mods: { 'type' : 'channels' },
    content: [
        { elem: 'title', content: 'Каналы' },
        { elem: 'container' }
    ]
}

// BEMHTML
block('list').elem('container').tag()('ul');

// JS-реализация загрузки данных в список
_getListData : function (type) {
    var container = this.elem('container');

    API.get('channels.list', { type: type }).then(function (data) {
        var channels = data.channels;

        channels.forEach(function (channel) {
            BEMDOM.append(container,
                BEMHTML.apply({
                    block : 'list',
                    elem : 'item',
                    mods : { type : type },
                    content : channel.name,
                    js : {
                        id : channel.id,
                        name : channel.name
                    }
                })
            );
        });
    });
}

Спасибо!

Расскажите, пожалуйста, как можно использовать loader_type_bundle

А я могу, каким-то образом получить bemjson, который соотвествует финальной верстке BEMHTML ?

т.е. например из

{
  block: 'widgets',
  content: [
    {
      elem: 'weather',
      content: 4
    }
  ]
}

вот это

{
  block: 'widgets',
  tag:"div",
  attrs: {
     class: "widgets i-bem",
     "data-bem": '{ "weather": { "id": 4321 } }'
  },
  content: [
    {
      elem: 'weather',  
      tag:"span",
      attrs: {
        class:"widgets__weather"
      },
      content: 4
    }
  ]
}

Ребят, у меня такая ситуация. Начинаю использовать bem-components и bemjson для прототипирования. Мне нужно заменить базовый желтый цвет (в этом есть необходимость именно для наших прототипов).

Какой самый "ювелирный" способ переопределять базовые цвета темы. Я правильно понимаю, что цвета у каждого компонента жестко прописаны, а не вынесены в переменные.? Нет возможности поменять значение где-то в одном месте, а нужно руками пробегаться по компонентам. Либо подключать свой файл стилей, где все переопределить.

Всем привет! Подскажите, пожалуйста. Есть код bemjson.js, который выводит две группы div'вов с соответсвтующим содержимым. В моем случае это группы

Library: 
    audio
    video
    software
Store:
    video

Сам код bemjson

{
block: 'media',
content: [
    {
    content: 'Library:',
    audio: 'audio',
    video: 'video',
    software: 'software'
    },
    {
    content: 'Store:',
    video: 'video'      
    }

    ].map(function(item) {
        return {
        block: 'library-item',
        mods: { image: 'yes' },
        content: {
            block : 'group',
            mix: { block: 'library-item', elem: 'group' },
            content : [
                {
                    elem: 'desc',
                    mix: { block: 'library-item', elem: 'desc' },
                    content: item.content
                },
                {
                    block: 'list',
                    mix: { block: 'library-item', elem: 'list' },
                    content: item.books

                },
                {
                    block: 'list',
                    mix: { block: 'library-item', elem: 'list' },
                    content: item.audio

                },
                {
                    block: 'list',
                    mix: { block: 'library-item', elem: 'list' },
                    content: item.video                                         
                },
                {
                    block: 'list',
                    mix: { block: 'library-item', elem: 'list' },
                    content: item.software

                }

            ]
        }

    };
    })
},

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

Здравствуйте. Имеется вот такой bemjson:

({
    block: 'page-part',
    content: [{
        block: 'liquid-if',
        conditions: [{
            condition: 'blabla !=2',
            content: [{
                block: 'tatata',
                content: [{
                    block: 'liquid-if',
                    conditions: [{
                        condition: 'tata == 3',
                        content: 'Hello!'
                    }]
                }]
            }]
        }]
    }]
})

Его обрабатывает вот такой bemhtml:

block('liquid-if')(
    bem()(false),
    match(function() { return this.ctx.conditions})(
        def()(function() {
            var ctx = this.ctx.conditions,
                arr = [];
            ctx.forEach(function(item, i) {
                if (typeof(ctx[i].condition) !== 'undefined') {
                    if (i === 0) {
                        arr.push('{% if '+ ctx[i].condition +' %}')
                    } else {
                        arr.push('{% elseif '+ ctx[i].condition +' %}')
                    }
                } else {
                    arr.push('{% else %}')
                }
                arr.push(ctx[i].content)
            });
            arr.push('{% endif %}');
            return applyCtx(arr)

        })
    )
);

На выходе получаем такой html:

{% if blabla !=2 %}
<div class="tatata">
    <div></div>
</div>{% endif %}

Вопрос: из-за чего вложенный блок не применяет шаблон по моде default, хотя bem()(false) отрабатывает?

Привет, всем! Мне необходимо разбить текст кнопки на два независимых элемента. Например, внутри кнопки написать "2 в третьей степени", чтобы число "2" имело свои стили, а степень свои.

Доброго времени!

Для создания проекта использовал «yo bem-stub». Выбранные основные технологии: bemtree, bemjson, bh. Выбранные уровни переопределения: desktop, touch-pad, touch-phone. Сборщик — ENB.

Как при описании блока «page», например, в «desktop.bundles/index/index.bemjson.js» не указывать параметр favicon, а использовать значение и ресурсы самого блока, переопределенного на уровне «common»?

Заранее спасибо за помощь!

В треде про использование БЭМ на небольших проектах Николай Громов пожаловался, что написание BEMJSON требует больше времени, чем написание HTML с помощью emmet.

И хотя время на набор кода не кажется чем-то существенным ни в процентном соотношении со временем на обдумывание или отладку, ни в абсолютных значениях, подумалось, что потратить несколько часов на написание аналога emmet для BEMJSON — это неплохой способ провести вечер ;)

Так появился пакет bemmet, который умеет разворачивать аббривиатуры вроде b1>__e1*2>b3_theme_islands+_state_active{hello} в BEMJSON:

{
    block: 'b1',
    content: [
        {
            block: 'b1',
            elem: 'e1',
            content: [
                {
                    block: 'b3',
                    mods: { theme: 'islands' },
                    content: {}
                },
                {
                    block: 'b1',
                    mods: { state: 'active' },
                    content: 'hello'
                }
            ]
        },
        {
            block: 'b1',
            elem: 'e1',
            content: [
                {
                    block: 'b3',
                    mods: { theme: 'islands' },
                    content: {}
                },
                {
                    block: 'b1',
                    mods: { state: 'active' },
                    content: 'hello'
                }
            ]
        }
    ]
}

Через опции можно конфигурировать кастомный нейминг — под капотом используется bem-naming. Метод stringify() поддерживает опции про индентацию и кавычки — используется stringify-object.

Попробовать bemmet в действии можно с помощью online-демки. Вы также можете сразу установить его в свой редактор с помощью плагинов для Sublime Text и Atom.

Буду благодарен, если кто-нибудь сделает плагины и для других редакторов.

Приятного использования!

Добрый день, я еще новенький в бэме, но подскажите, как вы оборачиваете, строите колонки из элементов на уровне bemhtml ? Поясню о чем я, например, пришел блок в bemjson:

{
    block: 'bootm',
    blk: [
        {
            inpval: '444',
            logo: '../../common.blocks/index/images/logo.png',
            url: '/',
            bagvar: '143',
            элем2: 'что то тут',
            элем3: 'что то тут'
        }
    ]
}

Вот если такой разметки будет мало:

elem('item')(
    tag()('li')
),
elem('title')(
    tag()('h3')
)

И тут мне, как бедному верстальщику, нужно из этих данных средствами bemhtml сделать раскрасивую конфетку, с колоночками, row' ами небольшими обертками, одним словом кастомную разметку на выходе, далекую от бутстрапа, вот тут и прошу совета в двух словах.

Всем привет!

Очень интересную ситуацию наблюдаю при сборке примеров для документации на разных платформах (Windows, Linux/OS X) с использованием пакетов enb-bem-examples и enb-magic-factory. На Windows сборка проходит без ошибок на остальных возникает следующая ошибка:

  ~/src/drom-bem-makeup   master ●  enb make examples -n
16:14:26.665 - build started
16:14:27.446 - [failed] [blocks.examples/common-desktop/common-desktop.bemjson.js] file-provider
16:14:27.448 - [failed] [blocks.examples/common-mobile/common-mobile.bemjson.js] file-provider
16:14:27.448 - [rebuild] [blocks.examples/b-button/ee3ZC6dyTetTRFqbHHZqKvywwXM/ee3ZC6dyTetTRFqbHHZqKvywwXM.bemjson.js] file-provider
16:14:27.448 - [rebuild] [blocks.examples/b-button/wrlcu38vmkNaP3tb9gvwZXBiszI/wrlcu38vmkNaP3tb9gvwZXBiszI.bemjson.js] file-provider
16:14:27.448 - [rebuild] [blocks.examples/b-button/PNXYUr__M6VSB4YxqCmkdMhk2l0/PNXYUr__M6VSB4YxqCmkdMhk2l0.bemjson.js] file-provider
16:14:27.449 - [rebuild] [blocks.examples/b-button/Ekw9TzRLS_fyQiOkC-Zi804eDzo/Ekw9TzRLS_fyQiOkC-Zi804eDzo.bemjson.js] file-provider
16:14:27.449 - [rebuild] [blocks.examples/b-button/9y8JjzeQPxlsleieuSrVga8xv4U/9y8JjzeQPxlsleieuSrVga8xv4U.bemjson.js] file-provider
16:14:27.449 - [rebuild] [blocks.examples/b-button/WgU-OFa8iJsKWLBtnoxXtfgoLCc/WgU-OFa8iJsKWLBtnoxXtfgoLCc.bemjson.js] file-provider
16:14:27.449 - [rebuild] [blocks.examples/b-link/D1rJB4_MGVvbnFlNUN1xUlQvtpQ/D1rJB4_MGVvbnFlNUN1xUlQvtpQ.bemjson.js] file-provider
16:14:27.449 - [rebuild] [blocks.examples/b-link/6O-IryxuQJM1YwYJYT_hHvf20NQ/6O-IryxuQJM1YwYJYT_hHvf20NQ.bemjson.js] file-provider
16:14:27.449 - [rebuild] [blocks.examples/b-button/kreyF1JOyT4hpa2NBRIP_KwvWkY/kreyF1JOyT4hpa2NBRIP_KwvWkY.bemjson.js] file-provider
16:14:27.449 - [rebuild] [blocks.examples/b-link/7PpftPzRoUzxzKCcgS8Xn51w1o/7PpftPzRoUzxzKCcgS8Xn51w1o.bemjson.js] file-provider
16:14:27.450 - [rebuild] [blocks.examples/b-link/28tLGFFUSZMApDlzg9Hi-09cNzg/28tLGFFUSZMApDlzg9Hi-09cNzg.bemjson.js] file-provider
16:14:27.450 - [rebuild] [blocks.examples/b-link/XCMcnEyp-kgOzxTPExe9Xyu6xUI/XCMcnEyp-kgOzxTPExe9Xyu6xUI.bemjson.js] file-provider
16:14:27.450 - [rebuild] [blocks.examples/b-link/uIFN2UGU4DNbCgT2JACquwcCSUo/uIFN2UGU4DNbCgT2JACquwcCSUo.bemjson.js] file-provider
16:14:27.450 - [rebuild] [blocks.examples/b-link/UgeVMmhNha9pAtahV7VjriQCt9I/UgeVMmhNha9pAtahV7VjriQCt9I.bemjson.js] file-provider
16:14:27.450 - [rebuild] [blocks.examples/b-link/xhSZr6XvNYk0AwDEfeLBCjtMs1g/xhSZr6XvNYk0AwDEfeLBCjtMs1g.bemjson.js] file-provider
16:14:27.450 - [rebuild] [blocks.examples/b-button/g7f-wx_WjkFq_MRA_Fzs9eRLCnQ/g7f-wx_WjkFq_MRA_Fzs9eRLCnQ.bemjson.js] file-provider
16:14:27.450 - [rebuild] [blocks.examples/m-button-ico/cUvu2JGXCO5KN8cmKNt11ZL40nI/cUvu2JGXCO5KN8cmKNt11ZL40nI.bemjson.js] file-provider
16:14:27.450 - [rebuild] [blocks.examples/b-link/xIo7WqepN6yOXUzXkxpVCwoPtLw/xIo7WqepN6yOXUzXkxpVCwoPtLw.bemjson.js] file-provider
16:14:27.450 - [rebuild] [blocks.examples/b-link/QD3PyE2oaSabCQ_mcdAbZliSAME/QD3PyE2oaSabCQ_mcdAbZliSAME.bemjson.js] file-provider
16:14:27.586 - [rebuild] [blocks.examples/common-desktop/common-desktop.levels] levels
16:14:27.586 - [rebuild] [blocks.examples/common-mobile/common-mobile.levels] levels
16:14:27.587 - [rebuild] [blocks.examples/b-button/ee3ZC6dyTetTRFqbHHZqKvywwXM/ee3ZC6dyTetTRFqbHHZqKvywwXM.levels] levels
16:14:27.587 - [rebuild] [blocks.examples/b-button/wrlcu38vmkNaP3tb9gvwZXBiszI/wrlcu38vmkNaP3tb9gvwZXBiszI.levels] levels
16:14:27.587 - [rebuild] [blocks.examples/b-button/PNXYUr__M6VSB4YxqCmkdMhk2l0/PNXYUr__M6VSB4YxqCmkdMhk2l0.levels] levels
16:14:27.587 - [rebuild] [blocks.examples/b-button/Ekw9TzRLS_fyQiOkC-Zi804eDzo/Ekw9TzRLS_fyQiOkC-Zi804eDzo.levels] levels
16:14:27.587 - [rebuild] [blocks.examples/b-button/9y8JjzeQPxlsleieuSrVga8xv4U/9y8JjzeQPxlsleieuSrVga8xv4U.levels] levels
16:14:27.587 - [rebuild] [blocks.examples/b-button/WgU-OFa8iJsKWLBtnoxXtfgoLCc/WgU-OFa8iJsKWLBtnoxXtfgoLCc.levels] levels
16:14:27.587 - [rebuild] [blocks.examples/b-link/D1rJB4_MGVvbnFlNUN1xUlQvtpQ/D1rJB4_MGVvbnFlNUN1xUlQvtpQ.levels] levels
16:14:27.587 - [rebuild] [blocks.examples/b-link/6O-IryxuQJM1YwYJYT_hHvf20NQ/6O-IryxuQJM1YwYJYT_hHvf20NQ.levels] levels
16:14:27.587 - [rebuild] [blocks.examples/b-button/kreyF1JOyT4hpa2NBRIP_KwvWkY/kreyF1JOyT4hpa2NBRIP_KwvWkY.levels] levels
16:14:27.587 - [rebuild] [blocks.examples/b-link/7PpftPzRoUzxzKCcgS8Xn51w1o/7PpftPzRoUzxzKCcgS8Xn51w1o.levels] levels
16:14:27.588 - [rebuild] [blocks.examples/b-link/28tLGFFUSZMApDlzg9Hi-09cNzg/28tLGFFUSZMApDlzg9Hi-09cNzg.levels] levels
16:14:27.588 - [rebuild] [blocks.examples/b-link/XCMcnEyp-kgOzxTPExe9Xyu6xUI/XCMcnEyp-kgOzxTPExe9Xyu6xUI.levels] levels
16:14:27.588 - [rebuild] [blocks.examples/b-link/uIFN2UGU4DNbCgT2JACquwcCSUo/uIFN2UGU4DNbCgT2JACquwcCSUo.levels] levels
16:14:27.588 - [rebuild] [blocks.examples/b-link/UgeVMmhNha9pAtahV7VjriQCt9I/UgeVMmhNha9pAtahV7VjriQCt9I.levels] levels
16:14:27.588 - [rebuild] [blocks.examples/b-link/xhSZr6XvNYk0AwDEfeLBCjtMs1g/xhSZr6XvNYk0AwDEfeLBCjtMs1g.levels] levels
16:14:27.588 - [rebuild] [blocks.examples/b-button/g7f-wx_WjkFq_MRA_Fzs9eRLCnQ/g7f-wx_WjkFq_MRA_Fzs9eRLCnQ.levels] levels
16:14:27.588 - [rebuild] [blocks.examples/m-button-ico/cUvu2JGXCO5KN8cmKNt11ZL40nI/cUvu2JGXCO5KN8cmKNt11ZL40nI.levels] levels
16:14:27.589 - [rebuild] [blocks.examples/b-link/xIo7WqepN6yOXUzXkxpVCwoPtLw/xIo7WqepN6yOXUzXkxpVCwoPtLw.levels] levels
16:14:27.589 - [rebuild] [blocks.examples/b-link/QD3PyE2oaSabCQ_mcdAbZliSAME/QD3PyE2oaSabCQ_mcdAbZliSAME.levels] levels
16:14:27.590 - build failed
16:14:27.597 - build failed
Error: File not found: /Users/rudoy/src/drom-bem-makeup/blocks.examples/common-desktop/common-desktop.bemjson.js
    at /usr/local/lib/node_modules/enb-bem-examples/node_modules/enb/techs/file-provider.js:47:49
    at FSReqWrap.cb [as oncomplete] (fs.js:212:19)

Кусок кода отвечающий за сборку примеров и их бандлов:

var factory = config.module('enb-magic-factory'),
        helper = factory.getHelper('examples');

    helper.prebuild(function(magicConfig){
        magicConfig.registerNode('blocks.examples/common-desktop');
        magicConfig.registerNode('blocks.examples/common-mobile');
    });

    helper.configure(function(config, nodes, targets){
        var nodes = nodes;
        config.nodes(nodes, function(nodeConfig){
            if(nodeConfig.getPath() === appConfig.examplesDir + '/common-desktop' || nodeConfig.getPath() === appConfig.examplesDir + '/common-mobile'){
                var depsDesktop = [],
                    depsMobile = [];

                nodeConfig.addTechs([
                    [ require('enb-bem-techs/techs/levels'), {levels: getExamplesLevels(config)} ],
                    [ enbBemTechs.files ],
                    [ techs.js ]
                ]);

                nodes.forEach(function (node) {
                    if (!/\/.*common.*/.test(node)) {
                        var pathNorm = path.normalize(node),
                            splitedPath = pathNorm.split(path.sep);

                        if(/m\-.\w*/.test(node)){
                            depsMobile.push(splitedPath[splitedPath.length - 1] + '.deps.js');
                            nodeConfig.addTechs([
                                //copy deps files to common-mobile dir
                                [ enbBemTechs.provideDeps, { node: pathNorm,  target: splitedPath[splitedPath.length - 1] + '.deps.js' } ],
                            ]);
                        }else{
                            depsDesktop.push(splitedPath[splitedPath.length - 1] + '.deps.js');
                            nodeConfig.addTechs([
                                //copy deps files to common-desktop dir
                                [ enbBemTechs.provideDeps, { node: pathNorm,  target: splitedPath[splitedPath.length - 1] + '.deps.js' } ],
                            ]);
                        }

                    }
                });

                //merge bundle
                if(nodeConfig.getPath() === appConfig.examplesDir + '/common-mobile'){
                    nodeConfig.addTechs([
                        [ enbBemTechs.mergeDeps, { sources:  depsMobile }]
                    ])
                }
                if(nodeConfig.getPath() === appConfig.examplesDir + '/common-desktop'){
                    nodeConfig.addTechs([
                        [ enbBemTechs.mergeDeps, { sources:  depsDesktop }]
                    ])
                }

                nodeConfig.addTechs([
                    //bemhtml
                    [ techs.bemhtml, { sourceSuffixes: [ 'bemhtml', 'bemhtml.js' ] } ],
                    //css
                    [ techs.cssStylus, {target: '?.noprefix.css'}],
                    [ techs.cssAutoprefixer, {
                        sourceTarget: "?.noprefix.css",
                        destTarget: '?.css',
                        browserSupport: ["> 2%", "last 2 versions", "Firefox ESR", "Opera 12.1", "Android >= 4", "iOS >= 5"]
                   }]
                ]);

                nodeConfig.addTargets(['?.js', '?.css', '?.bemhtml.js']);

            }else {
                nodeConfig.addTechs([
                    [require('enb-bem-techs/techs/levels'), {levels: getExamplesLevels(config)}],
                    [enbBemTechs.bemjsonToBemdecl],
                    [enbBemTechs.depsOld],
                    [enbBemTechs.files],
                    //CSS
                    [techs.cssStylus, {target: '?.noprefix.css'}],
                    [techs.cssAutoprefixer, {
                        sourceTarget: "?.noprefix.css",
                        destTarget: '?.css',
                        browserSupport: ["> 2%", "last 2 versions", "Firefox ESR", "Opera 12.1", "Android >= 4", "iOS >= 5"]
                    }],
                    //BEMHTML
                    [techs.bemtree, {sourceSuffixes: ['bemhtml', 'bemhtml.js']}],
                    //BEMHTML
                    [techs.bemhtml, {sourceSuffixes: ['bemhtml', 'bemhtml.js']}],
                    //HTML
                    [techs.htmlBeautify],
                    [techs.htmlFromJSON],
                    //client JS
                    [techs.browserJs],
                    [techs.fileMerge, {target: '?.pre.js', sources: ['?.bemhtml.js', '?.browser.js']}],
                    [techs.prependYm, {source: '?.pre.js'}]
                ]);

                nodeConfig.addTargets(['?.js', '?.css', '?.html', '?.browser.js', '?.beauty.html', '?.bemtree.js']);
            }
        });
    });

Ошибка возникает на этапе сборки бандлов(common-desktop и common-mobile) . При сборке которых нет необходимости провайдить .bemjson.js.

Не много дебага с помощьюnode.getTechs().

if(nodeConfig.getPath() === appConfig.examplesDir + '/common-desktop' || nodeConfig.getPath() === appConfig.examplesDir + '/common-mobile'){
           console.log(nodeConfig.getTechs());
           ......
}

На Windows результат будет пустой на OS X/Linux [ { _options: { target: '?.bemjson.js' } } ]

Хотелось бы разобраться, почему сборка ведет себя по разному на разных платформах?

Ребят подскажите какой инструмент использовать для подсветки синтаксиса? Помимо верстки делается руководство стиля оно представляет собой ту же сборку bem блоков Сейчас юзаю prism.js, но так как enb в процессе сборки сжимает код в строку результат получается в строку, а хочется что бы с отступами и новыми строками.

Ребята, помогите решить задачку, хочется сделать по уму:

У меня есть две страницы в bundles: page1 и page2. Эти страницы очень похожи, разница в том, что page2 немного более расширена ( добавляются информационные блоки). В результате нужно иметь две страницы с чистым исходным кодом ( чтобы дополнительные блоки были только на странице page2).

Так как дизайн дорабатывается, да и для удобства поддержки, не хочется дублировать одинаковые на этих двух страницах вещи. Одинаковый блок, кроме текста, содержит ещё компоненты ( как стандартные из bem-components, так и самописные), да и вообще, представляет собой внушительную портянку.

Как сделать правильнее? Я пока вижу такие варианты:

  1. создать блок common_page и в bemhtml прописать там всю информацию для общей информации. После этого, подключать этот блок на странице page1 и page2. Отсюда возникают вопросы, правильно ли писать столько html в данном случае ( в bemjson около 1500 строк кода ) и будут ли работать стандартные и самописные компоненты? Ну и, конечно, переписывать 1500 строк кода совсем не хочется.
  2. придумать что-то типа @import(page1) для страницы page2. Возможно ли такая реализация?
  3. попытаться решить через модификатор ( расширенная страница - page2 или обычная - page1). Но при этом у меня должно в bundles так и остаться 2 физические страницы с чистым кодом. Как тогда организовать работу модификатора?

Еще не розобрался, хедер : слева лого-картинка справа кнопка входа меню : 4 кнопки ссылки по горизонтали основа : 1 блок контейнер с иконками 2 блок что-то похожее на календать 3 блок аналогичен 2му 4 - кнопака слева, картинка справа футер : бэкграунд 3 таблицы с текстом

При создании дерева в хедере - логотип пропадает остается только кнопка.

Здравствуйте. Подскажите, как можно добавить тег внутри текста? Например

block: 'text',
content: 'ТекстТекстТекст<a class='link' href="">Текст</a>ТекстТекстТекстТекстТекстТекст'

Можно такого добиться с помощью bemjson как нибудь?

Всем привет!

Правильно ли я объявляю блок-микс в js? Он у меня почему-то выпадает в ошибку: Uncaught mix block "mix" for "block" is undefined.

BEMJSON:

{
        block: 'block',
        js: true,
        mix: [{block: 'mix'}],
        content: 'Block'
    }

js:

modules.define('block', ['i-bem__dom'], function(provide, BEMDOM) {

    provide(BEMDOM.decl({ block: this.name, baseMix: ['mix'] }, {
        onSetMod: {
            'js': {
                'inited': function() {
                    console.log('Block!')
                }
            }
        }
    }));

});

Во времена React.js и подобных вещей хочется и в bem.js чего то подобного.

Из дискуссии https://ru.bem.info/forum/385/ ничего внятного не вышло. Предлагаю вариант своей идеи как это можно сделать.

Основная идея

По аналогии с React оперировать виртуальным деревом, но не в терминах DOM а в терминах БЭМ. При загрузке страницы вместе с базовым HTML телом страницы отдается bemjson и скомпилированный bemtree или bemhtml. Создается виртуальное БЭМ дерево, далее из него формируется html и рендерится на страницу.

Пример

На текущий момент bem.js оперирует DOM нодами посредством jQuery. Нужна реализация оперирующая БЭМ деревом (по факту развернутый bemjson) и обновляющая данные на странице при его изменении.

Скажем браузеру отдается страница вида

<!-- index.html -->
<!DOCTYPE html>
<html>
  <head>
    <title>Hello</title>
  </head>
  <body class="page" bem-json="....">
// тут может быть отрендереный на сервере bemjson
  </body>
</html>

Сам bemjson имеет вид

{
    block: 'comment-box',
    js: {
        url: 'comments.json',
        pollInterval: 2000
    },
    content: [
        {
            block: 'comment-list',
            content: [
                {
                    author: 'Pete Hunt',
                    content: 'This is one comment'
                },
                {
                    author: 'Jordan Walke',
                    content: 'This is *another* comment'
                }
            ]
        }
    ]
}

Ну и сами блоки

JSONBEMDOM.decl('comment-box', {
    onSetMod: {
        js: {
            inited: function() {
                // метод findBlockInside спускается по нашему виртуальному БЭМ дереву
                // и пытается найти bemjson блок comment-form 
                this.form = this.findBlockInside('comment-form');
                this.commentsList = this.findBlockInside('comment-list');

                this.form.on('submit', this._submitHandler);

                this._loadCommentsFromServer();
                setInterval(this._loadCommentsFromServer, this.params.pollInterval);
            }
        }
    },

    getDefaultParams: function() {
        return {
            data: [],
            url: '',
            pollInterval: null
        }
    },

    _loadCommentsFromServer: function() {
        $.getJson(this.params.url).done(function(comments) {
            /**
             * метод content() ожидает аргумент в синтаксисе bemjson
             * который он применяет к `content` параметру блока в виртуальном БЭМ дереве
             */
            this.commentsList.content(comments);
        }.bind(this));
    },

    _submitHandler: function(e) {
        e.preventDefault();
        /**
         * метод content() без аргументов отдает из дерева
         * параметр `content` элемента, если это инпут то его значение
         */
        var text = this.elem('text').content();
        var author = this.elem('author').content();

        $.post(this.params.url, {
            text: text,
            author: author
        }).done(function (comment) {
            var comments = this.commentsList.content();
            comments = comments.concat([comment]);

            this.commentsList.content(comments);
        }.bind(this));
    }
});

bem.js сам отслеживает изменения в виртуальном БЭМ дереве, делает слепок отличий, накладывает на него bemhtml/bemtree и инъектит его в текущий html.

В итоге мы имеем на клиенте

  • Всю мощь декларативной шаблонизации bemhtml/bemtree
  • Красивый и структурированный bemjson на клиенте
  • Производительность из-за виртуального БЭМ дерева.

Привет ребят. Я не могу понять для чего нужен elem в bemjson. Ведь можно всё сделать через блоки, и при необходимости использовать mix для того, чтобы доопределить что нибудь? Или я скорей всего чего то не догоняю) Подскажите пожалуйста?

Можно ли добавить условие в bemjson что бы блок написаный мной показывался только в IE > 9, по аналогии

{
    elem : 'conditional-comment',
    condition : '< IE 9',
    content : [
        { elem : 'js', url : '//yastatic.net/es5-shims/0.0.1/es5-shims.min.js' },
        { elem : 'js', url : '/js/modernizr-html5shiv-respond.min.js' }
    ]
},

Имея такой bemjson

    {
            block: 'blur',
            js: true,
            content:{
                elem: 'image',
                url: '/img/background-blur/background-gradient.jpg'
            }
        }

Ожидаю что появиться на блоке модификатор js_inited Но его нет, i-bem есть, не могу понять почему на некоторых блоках все ок и инициализация есть, а на некоторых не появляется? Js написан для блока.