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

Всем привет!! Понимания схемы работы динамического сайта - нет. Есть понимание работы динамических страниц сайта в схеме:

  • MySQL(db) -> PHP ->HTML. В такой схеме робот индексирует страницу как HTML. Предполагаю что схема выглядит так:
  • MySQL(db) -> BEMTREE -> BEMJSON -> HTML А как происходит при схеме по БЭМ-шаблонам? Как индексируются сайты с движком JS, вместо PHP ???

Добрый день! Выдается такая ошибка Module "profit-metal": can't resolve dependence "BEMHTML"

при подключении технологии в файле js modules.define('profit-metal', ['i-bem-dom','BEMHTML', 'jquery'], function(provide, bemDom, BEMHTML, $)

кэш чистил, пробовал такой вариант, ошибка весит.

({
    tech : 'js',
    mustDeps : [
        { tech : 'bemhtml', block : 'i-bem' }
    ]
})

Недавно пришлось пописать на PUGJS... долго не смог это терпеть. Пришлось запилить 100 строчек кода, что бы писать нормальные шаблоны на BEMHTML в ExpressJS.

Код доступен как модуль https://www.npmjs.com/package/express-bem-xjst

Он умеет правильно работать с уровнями, кешируется и даже ничего не портит. Пробовал подключать bem-components — шаблонизирует все правильно.

Приятного использования тем, кто больше не может использовать ничего кроме BEM-XJST в шаблонах 😉

Пытаюсь подружить enb-bem-i18n с project-stub на express + bem-core и не получается.

Вот мой make.js:

var techs = {
        // essential
        fileProvider: require('enb/techs/file-provider'),
        fileMerge: require('enb/techs/file-merge'),

        // optimization
        borschik: require('enb-borschik/techs/borschik'),

        // css
        postcss: require('enb-postcss/techs/enb-postcss'),
        postcssPlugins: [
            require('postcss-import')(),
            require('postcss-each'),
            require('postcss-for'),
            require('postcss-simple-vars')(),
            require('postcss-calc')(),
            require('postcss-nested'),
            require('rebem-css'),
            require('postcss-url')({ url: 'inline' }),
            require('autoprefixer')(),
            require('postcss-reporter')()
        ],

        // js
        browserJs: require('enb-js/techs/browser-js'),

        // bemtree
        bemtree: require('enb-bemxjst/techs/bemtree'),

        // bemhtml
        bemhtml: require('enb-bemxjst/techs/bemhtml'),

        // i18n
        i18n: require('enb-bem-i18n/techs/i18n'),
        keysets: require('enb-bem-i18n/techs/keysets')
    },
    enbBemTechs = require('enb-bem-techs'),
    levels = require('./levels');

module.exports = function(config) {
    var isProd = process.env.YENV === 'production';

    config.setLanguages(['en', 'ru']);

    config.nodes('desktop.bundles/*', function(nodeConfig) {
        nodeConfig.addTechs([
            // essential
            [enbBemTechs.levels, { levels: levels }],
            [techs.fileProvider, { target: '?.bemjson.js' }],
            [enbBemTechs.bemjsonToBemdecl],
            [enbBemTechs.deps],
            [enbBemTechs.files],

            // i18n
            [techs.keysets, {
                lang: '{lang}'
            }],
            [techs.i18n, {
                lang: '{lang}',
                exports: { globals: 'force' }
            }],

            // css
            [techs.postcss, {
                target: '?.css',
                oneOfSourceSuffixes: ['post.css', 'css'],
                plugins: techs.postcssPlugins
            }],

            // bemtree
            [techs.bemtree, { sourceSuffixes: ['bemtree', 'bemtree.js'] }],

            // bemhtml
            [techs.bemhtml, {
                sourceSuffixes: ['bemhtml', 'bemhtml.js'],
                forceBaseTemplates: true,
                engineOptions: { elemJsInstances: true },
                requires: {
                    i18n: { globals: 'BEM.I18N' }
                }
            }],

            // i18n merge
            [techs.fileMerge, {
                target: '?.{lang}.bemhtml.js',
                lang: '{lang}',
                sources: ['?.bemhtml.js', '?.lang.{lang}.js']
            }],

            // client bemhtml
            [enbBemTechs.depsByTechToBemdecl, {
                target: '?.bemhtml.bemdecl.js',
                sourceTech: 'js',
                destTech: 'bemhtml'
            }],
            [enbBemTechs.deps, {
                target: '?.bemhtml.deps.js',
                bemdeclFile: '?.bemhtml.bemdecl.js'
            }],
            [enbBemTechs.files, {
                depsFile: '?.bemhtml.deps.js',
                filesTarget: '?.bemhtml.files',
                dirsTarget: '?.bemhtml.dirs'
            }],
            [techs.bemhtml, {
                target: '?.browser.bemhtml.js',
                filesTarget: '?.bemhtml.files',
                sourceSuffixes: ['bemhtml', 'bemhtml.js'],
                engineOptions: { elemJsInstances: true }
            }],

            // js
            [techs.browserJs, { includeYM: true }],
            [techs.fileMerge, {
                target: '?.js',
                sources: ['?.browser.js', '?.browser.bemhtml.js']
            }],

            // borschik
            [techs.borschik, { source: '?.js', target: '?.min.js', minify: isProd }],
            [techs.borschik, { source: '?.css', target: '?.min.css', minify: isProd }]
        ]);

        nodeConfig.addTargets([
            '?.bemtree.js',
            '?.min.css',
            '?.min.js',
            '?.lang.{lang}.js',
            '?.{lang}.bemhtml.js'
        ]);
    });
};

Все собирается успешно, но в момент старта приложения получаю ошибку:

/Users/anakatata/Desktop/test/desktop.bundles/index/index.ru.bemhtml.js:3401
            i18n: global['BEM']['I18N'],
                               ^

TypeError: Cannot read property 'I18N' of undefined

В чем может быть проблема?

Задача миграции проектных шаблонов

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

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

Приведу еще раз все необходимые шаги для последовательной миграции шаблонов с bem-xjst v1.x до v8.x здесь.

bem-xjst v1.x → v2.x

  • def() режим должен возвращать хоть что-то.
  • все поля шаблонизатора доступные ранее в this._ теперь переехали просто в this.
  • нет больше mode('') (режима с пустым именем), используйте def().
  • подпредикат block(…) теперь обязателен для всех шаблонов.
  • this._str больше не существует.
  • изменилось поведение apply('modeName').
  • результат вызова режима tag() теперь имеет приоритет над полем tag из BEMJSON-а.

bem-xjst v2.x → v3.x

  • apply.call(BEMJSON) нужно исправить на apply(BEMJSON).

bem-xjst v3.x → v4.x

  • block('b').wrap()(function() { … }) вместо block('b').wrap().def()(function() { return applyCtx({ … }); }).

bem-xjst v4.x → v5.x

  • Необходимо заменить elemMatch(argument) на elem('*').match(function() { ... }). elemMatch() упразднен.
  • Поведение полей mods и elemMods в BEMJSON изменено. bem-xjst больше не будет воспринимать mods как elemMods.
  • API изменено: require('bem-xjst') теперь возвращает два движка bemhtml и bemtree. Просто замените require('bem-xjst') на require('bem-xjst').bemhtml.

bem-xjst v5.x → v6.x

  • результат вызова режима tag() теперь имеет приоритет над полем tag из BEMJSON-а.

bem-xjst v6.x → v7.x

  • this.isArray() устарел, используем Array.isArray().
  • once() устарел и выпилен, используем просто def().
  • Теперь bem-xjst для сравнения значения модификатора из подпредиката шаблона и из BEMJSON-а предварительно приведет значение из BEMJSON-а к строке. Это может вызвать несоответствие поведения с версией v6.x. Поэтому считаем хорошей практикой, когда значения модификаторов — строка. Пример, результат которого можно сравнить в v6.x и v7.x
  • Опционально: v6.x по умолчанию генерила закрывающие слеши у одиночных тегов. В v7.x это поведение отменено и она по умолчанию генерит HTML а не XHTML. Чтобы вернуть закрывающие слеши можно воспользоваться опцией bem-xjst xhtml: true.

bem-xjst v7.x → v8.x

  • Для обратной совместимости необходимо заменить режимы mix() на addMix(), attrs() на addAttrs(), js() на addJs().

Автомигратор

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

Автомигратор доступен в bem-xjst v7.x и v8.x (актуальные версии) и умеет править код проектных шаблонов так, чтобы он начал соответствовать указанной мажорной версии.

Под капотом обычный jscodeshift и тесты на трансформации кода. Если появятся какие-либо вопросы после прочтения документации создавайте issue в репозитории шаблонизатора.

Статический линтер

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

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

Подскажите как сделать так, чтобы по файлу BEMJSON папки и файлы(стилей скриптов и др) создавались сами.

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

P.S. Чтобы подключить bem-tools нужно на уровне проекта прописать npm install bem верно ? или просто в терминале это прописать? Куда он тогда установится

P.P.S. В документации к тулзу написанно, что можно создавать для БЭМ сущностей css, js файлы, а так же bemhtml. Нужно ли это делать или bemhtml идет один на бандл(страницу).

Платформа/Шаблоны (BEMHTML, BEMTREE)/Быстрый старт/online demo https://bem.github.io/bem-xjst/

В результирующем коде должен быть элемент 'image'. Но его нет. Пытаюсь повторить блок с логотипом на своем проекте. И не могу врубиться что не так с кодом.

Подскажите - в чем дело!?

Привет помогите пожалуйста, почему я все никак не могу получить bemhtml на клиенте вроде все ок и зависимости и все позвал. и да такой вопрос если я все пишу через bemtree (ну как bemhtml у меня чисто для тегирования и атрибутов, то есть пока там только разная мелочь) и по сути у меня нет шаблона я просто хочу использовать сам шаблонизатор на клиенте, что я делаю не так?

modules.define('manager', ['i-bem__dom', 'BEMHTML', 'menu', 'jquery'], function(provide, BEMDOM, BEMHTML, MenuEvent, $) {

    provide(BEMDOM.decl(this.name, {
        onSetMod : {
          'js' : {
            'inited' : function() {
                MenuEvent.on('update', this._taskUpd, this);
            }
          }
        },
        _taskUpd : function () {

            this.setMod(this.elem('content'), 'action', 'artAdd');

            var bemjson = {
                block: 'content',
                content: [
                ]
            };

            var html = BEMHTML.apply(bemjson);

            console.log(html);

            BEMDOM.update(this.elem('content'), html);

            return false;
        }
    }));

});

зависимости

({
  shouldDeps: [
      { elem: 'control'},
      { elem: 'content'},
      { mods: { action: 'article'} },
    { block: 'modal', mods : { theme : 'islands', autoclosable : true }},
    'button',
    'content',
    'menu',
    { block: 'i-bem', elem: 'dom' },
    { tech: 'js', mustDeps: { elem: 'content', tech: 'bemhtml' } }
  ]
})

Историческая справка

До недавнего времени мы работали над возможностью генерации Virtual DOM на основе BEMHTML-шаблонов. Мы разработали специальный движок для bem-xjst – xjst-ddsl, который может превращать шаблоны в некий DDSL, который с помощью дополнительного хелпера – ddsl-react превращался в React. Это было сделано для того, чтобы отделить специфику React и сделать закладку на тот случай, если захочется другую реализацию Virtual DOM. Об этом рассказывал я, например, на Я.Субботнике. Мы выдвинули и даже математически доказали гипотезу об эффективности этого метода, поскольку он позволял в 10 раз ускориться на сервере относительно нативного рендеринга на React, ведь на сервере мы можем использовать стандартный рендер в HTML, так как шаблоны одни.

Спустя некоторое время

Все это время мы делали подход в опенсоре – react-bl и внутри на реализацию компонентов для React на BEMHTML-шаблонах. Внутри мы попробовали очень большой объем компонентов, в том числе и составные/сложные с попапами и модальными окнами.

В чем разница открытой версии и внутренней?

В react-bl мы пробовали писать React-код для клиента "сверху" верстки и шаблонов, чтобы не трогать сами шаблоны и пробрасывать биндинги через пропсы компонентов. То есть получался "настоящий" React-компонент, где только разметка генерировалась с помощью BEMHTML. Такой подход нёс в себе несколько проблем. Во-первых, не работали уровни переопределения для клиентского кода, только для верстки в шаблонах. Во-вторых, добавлял иногда большие трудности при пробрасывании пропсов во вложенные элементы, тем более, если они строились динамически и имели вариативность.

Основываясь на этом опыте внутри мы попробовали писать клиентский код прямо в BEMHTML шаблонах. Например так:

block('link')(
   tag()('a'),
   js()(function() {
      return {
        onClick: () => console.log('hi there')
      };
   })
);

Это позволило решить проблемы с уровнями переопределения. И декларацией клиентского кода для вложенных элементов. Но... Нам пришлось добавить немного магии в ddsl-react (тот самый хелпер, что превращает DDSL в React). Мы добавили автоматический биндинг контекста. Ведь клиентский код в шаблонах ничего не знал про инстанс React-компонента и мы сделали это автоматически.

Кроме того, скорее всего вы спросите...

Как же было дело со вложенными компонентами?

Вопрос о том, что если кнопка использует иконку, а иконка тоже компонент? Ведь вызов иконки описан в BEMHTML и это просто BEMJSON, а не какой ни React-component. Мы решили эту проблему полуавтоматически: во время обьявления класса мы используем хелпер (ddsl-react), который первым аргументом принимает обьект с матчингом блоков на React-компоненты. Внутри во время рендера, когда встречается блок из матчинга он подменяется на React-компонент. Ведь разработчик знает, что за блоки используется в составном среди BEMHTML.

Что стало?

К сожалению, мы не учли несколько нюансов, и как мы ни пытались их обойти, сделать это эффективно у нас не получилось. А именно:

  • проблема автоматического биндинга контекста: это очень большая магия и возникают неоднозначности при обращении к элементам из блока или к другим элементам из элемента
  • проблема проставления refs, в 99% случаев все хорошо, но только не когда нужен ref на вложенный элемент в блоке, который вложен в другой блок
  • слишком строгие правила для написания шаблонов чтобы серверный рендер работал действительно быстро. То есть клиентский код должен быть вынесен в другой уровень относительно верстки и это надо учитывать в сборке. В противном случае среди рендера BEMHTML функции React по прежнему выполнялись, что сильно замедляло процесс

Всё прям плохо?

На самом деле нет. В 99% случаев решение работает и работает хорошо. Просто ожидаемый профит показался недостаточным. Нам хотелось быстрый рендер на сервере и удобное написание React-компонентов. Опытным и трезвым умом нам показалось что мы этого не достигли. Тем не менее использовать BEMHTML-шаблоны в React можно, но базировать на этом библиотеку с компонентами не стоит. Если у вас есть желание работать с этим решением, я с радостью помогу разобраться и раздам прав. Мейнетейнеры нынче в цене.

Что дальше?

Мы проверяем новую гипотезу в bem-react-core. Это очень маленькая по обьему библиотека, которая позволяет декларировать React-компоненты в BEMHTML подобном синтаксисе, писать на последнем стандарте, собираться чем угодно(webpack, gulp, rollap, babel), поддерживает уровни переопределения и все все, что мы так любим. В репозитории есть набор примеров, которые можно посмотреть и понять. Мы работаем над новым набором компонентов в bem-react-components. Внутри мы так же попробовали очень много компонентов и кажется все очень хорошо. У нас уже почти готова документация и скоро она появится в репозитории. И так же скоро появится поддержка i18n ;) Приходите с PR и хейтерством. Все что мы запланировали пока, кажется отражено в issues.

Код для привлечения внимания

у нас есть несколько разделов сайта. Админка, профиль, публичная часть. Сейчас собирается 3 merged бандла. При этом на публичной части много разных страниц. Хотелось бы иметь что то вроде core.js, core.css куда попадут стили и скрипты общие для всех страниц публичной части, и маленькие js и css для каждой отдельной страницы, где будут уникальные стили-скрипты для нее. Как это сделать?

Здача: матчить элемент блока с модификатором. Вроде бы должно быть так ведь: block('b').mod('m', true).elem('e')( ... );? Сам по себе блок+мод отлавливается замечательно: block('b').mod('m', true). Аналогично -- вложенный элемент block('b').elem('e')( ... );. Но всё вместе никак почему-то не удаётся. Что я делаю не так?

Хочу в шаблоне выбрать (по имени) вложенные в блок элементы и... ч.-ндь к ним применить.

Вижу, что в match у меня this.elem всегда undefined, а elemMatch (про который где-то что-то попадалось) почему-то отсутствует.

Как правильно поступить?

По ходу своей работы, часто сталкиваюсь с ajax запросами внутри i-bem блоков. Часто повторяющиеся паттерны решил вынести в отдельную надстройку над jquery.ajax.

Где можно использовать?

Допустим у вас есть кнопка, которая по клику на себя, добавляет куда то контент, а когда контента нет, удаляет сама себя

_onButtonClick: function () {
    Http
        .abortable(this)
        .get(this.params.url)
        .then(function (response) {
            BEMDOM.replace(this.domElem, response.getText());
        }.bind(this));
}

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

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

_onButtonClick: function () {
    Http
        .once(this)
        .get(this.params.url)
        .then(function (response) {
            this.showModal(response.getText());
        }.bind(this));
}

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

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


this._req = Http.abortable(this);

this._req.get(this.params.someUrl).then(this._onSomeDone); //этот запрос отменится, т.к следом идет другой
this._req.get(this.params.anotherUrl).then(this._onAnotherDone);

Не нужно плодить дополнительных переменных, самому вызывать abort() у jqXHR перед другим запросом.

Или если нужно сделать два разных запроса в разные места

Http.abortable(this, 'some').get(this.params.someUrl).then(this._onSomeDone);
Http.abortable(this, 'another').get(this.params.anotherUrl).then(this._onAnotherDone);

https://github.com/JiLiZART/bem-http

Ставим через bower install bem-http, и подключаем в уровнях { path: 'libs/bem-http/common.blocks', check: false }.

Пример как использовать в блоке https://github.com/JiLiZART/bem-http/blob/master/example.blocks/app/app.js

P.S. Если есть какие либо идеи по улучшению API, буду очень благодарен.

BEMJSON:

        {
            block: 'menu',
            elem: 'content'
        }

нужно получить:

        {
            block: 'menu',
            elem: 'content'
        },
        {
            block: 'menu',
            elem: 'overlay'
        },

c помощью шаблона:

block('menu').elem('content')(
    tag()(false),
    content()(function() {
        return [
            {
                elem: 'content2',
            },
            {
                elem: 'overlay'
            }
        ]
    })
);

можно получить почти то, что нужно, а но заменить элемент content2 на content не получается.

Добрый день! Начал верстку интернет-магазина в котором более 30 страниц. И тут же заказчику уже захотелось кое-что поменять в шапке. Страшно представить, что когда будет сверстан весь проект и начнутся правки, то придется ходить по ВСЕМ страницам и менять что-то в одинаковых блоках (header, footer, menu, rightbar и т.д.). Это будет просто самоубийство, и при всём уважении к данной методологии и её способности увеличивать скорость создания проектов, для данного случая эту будет намного дольше. Я пересмотрел и перечитал уже кучу материалов, но, блин, не могу сделать, чтобы это было корректно и удобно. Подскажите кто-нибудь, пожалуйста, как такое реализовать. Ведь полюбому есть решения данной проблемы, т.к. БЭМ используется, в основном, в крупных проектах. Прям очень очень прошу помощи и указать как такое реализовать, потому что не хочется, особенно при верстке такого крупного проекта, отказываться от БЭМ. Да, использую в качестве сборщика gulp, т.е. как реализовать это всё на нём. Спасибо!

Добрый день, Не могу понять в чем дело. Наверное, какая-то глупая ошибка. Я пытаюсь примиксовать стили к input и select в блоке qa-form.

.bemjson.js

        block: 'qa-form',
        url: "http://guk/api/feedback",
        content: [
            {
                elem: 'fields',
                content: [
                    {
                        block: 'input',
                        mods: {'has-clear': true},
                        name: 'flexibility'
                    },
                    {
                        block: 'select',
                        mods: {mode: 'radio'},
                        name: 'slenderness',
                        val: 1,
                        options: [
                            {val: 1, text: 'Report'},
                            {val: 2, text: 'Workshop'},
                            {val: 3, text: 'Round-table conference'}
                        ]
                    }
                ]
            }
        ]

qa-form.bemhtml.js

block('qa-form') ( js()(true),

tag()('form'),

block('input').mix()({  mods: {theme: 'islands', size: 'm'} }),
block('select').mix()({mods: { theme: 'islands', size: 'm'}}),

attrs()(function () {
    return {action: this.ctx.url};
})

);

qa-form.deps.js ({ mustDeps: [ {block: 'input', mods: {theme: 'islands', size: 'm'}}, {block: 'select', mods: {theme: 'islands', size: 'm'}}, ] })

В результате для input стили подключаются, а для select нет. Позже я понял, что внутри select есть блоки button и popup, для которых стили не подключаются. Если сделать так:

qa-form.bemhtml.js

block('qa-form') ( js()(true),

tag()('form'),

block('input').mix()({  mods: {theme: 'islands', size: 'm'} }),
block('select').mix()({mods: { theme: 'islands', size: 'm'}}),
block('button').mix()({mods: { theme: 'islands', size: 'm'}}),
block('popup').mix()({mods: { theme: 'islands', size: 'm'}}),

attrs()(function () {
    return {action: this.ctx.url};
})

);

qa-form.deps.js ({ mustDeps: [ {block: 'input', mods: {theme: 'islands', size: 'm'}}, {block: 'select', mods: {theme: 'islands', size: 'm'}}, {block: 'button', mods: {theme: 'islands', size: 'm'}}, {block: 'popup', mods: {theme: 'islands', size: 'm'}}, ] })

То стили подключаются и для select, но он не работает (кнопка не нажимается). Видимо почему-то js не подключается.. P.S. Извините, не понял как здесь правильно вставлять код, чтобы все было красиво.

Не понял, как в bemhtml работает маска * для элементов (в соотв. с синтаксисом шаблонов: "...В качестве name можно использовать '*'..."). Но пробую:

block('block_name').elem('*')( /* ... */ )

-- и получается, что находятся элементы, не только принадлежащие блоку block_name. Если правильно понял, находятся вообще ВСЕ элементы.

Что-то не так понял? Что-то не так делаю?

BEMHTML.apply() всегда возвращает пустую строку. Что-то тут не так.

var BEMHTML;

(function(global) {
    function buildBemXjst(__bem_xjst_libs__) {
        var exports = {};

        exports.apply = function () { return ""; };

        return exports;
    };



    var defineAsGlobal = true;

    // Provide with CommonJS
    if (typeof module === 'object' && typeof module.exports === 'object') {
        exports['BEMHTML'] = buildBemXjst({

}
);
        defineAsGlobal = false;
    }

    // Provide to YModules
    if (typeof modules === 'object') {
        modules.define(
            'BEMHTML',
            [],
            function(
                provide

                ) {
                    provide(buildBemXjst({

}
));
                }
            );

        defineAsGlobal = false;
    }

    // Provide to global scope
    if (defineAsGlobal) {
        BEMHTML = buildBemXjst({

}
);
        global['BEMHTML'] = BEMHTML;
    }
})(typeof window !== "undefined" ? window : global || this);

Где-то попадалась статья (или пост), не могу сейчас найти.

Задача: "подмешать" к основному блоку функционал другого.

В простейшем варианте (то, что заработало) получается во время инициализации первого сказать примерно так:

var second_block_object = this.domElem.bem('second_block');

-- тогда имею почти то, что нужно: объект второго блока, ассоциированный с dom-узлом.

Но хотелось бы уметь указывать необходимость примеси из шаблонов и оттуда же передавать параметры второму блоку (js()({ ... })). К сожалению, через mix таким образом подцепить нужный блок не удаётся. Как это делается правильно? (Как-то ведь делается?.. Вроде бы видел даже примеры...)

Добрый вечер!

Хочу собирать html на node.js сервере, используя следующий код:

var BEMHTML = require('./bundle/bundle.bemhtml.js').BEMHTML; var html = BEMHTML.apply(dataObject);

Где dataObject приходит такой: https://gist.github.com/philipusis/e98ea5bd6086d108e01adbc162cf26b9 Проблема в том, что для блока 'header' не применяется мой пользовательский шаблон, хотя в bundle.bemhtml.js он попадает: https://gist.github.com/philipusis/ef74ee8e1f63fb3300c83e5d6dfe58e0

HTML блока page генерируется нормально, т.е. библиотечные шаблоны работают нормально, а для header генерируется дефолтный

, который он берет из bemjson'а в dataObject. Полный код файла, который осуществляет сборку: https://github.com/philipusis/sixth-bem/blob/static_resources/render.js Допускаю, что где-то мог накосячить с конфигом для сборки, поэтому его можно посмотреть здесь: https://github.com/philipusis/sixth-bem/blob/static_resources/.enb/make.js

Подскажите, пожалуйста, что я забыл прописать?

Спасибо!

Доброго времени суток, при использовании bem-core появилась необходимость изменить стандартного блока page, не хотелось бы делать его дубликат, хотелось именно изменить/заменить.

хотелось бы узнать как правильно это делать

Привет. Наверное, стоит отдельно попиарить, что теперь в bem-xjst есть опция runtimeLint. С помощью неё вы сможете получать предупреждения о нежелательных или опасных местах в ваших шаблонах и входных данных (BEMJSON-е). Включить опцию можно начиная с версии 7.2.0 вот так. Предупреждения можно будет поймать в STDERR.

Вот краткое описание какого рода проверки выполняются уже сейчас.

Булевы атрибуты

Актуально для тех, чей проект раньше использовал шаблонизатор версии ниже чем v4.x. Пример BEMJSON-а: { tag: 'input', attrs: { disabled: true } } Результат с v4.3.2: <input disabled=“true”/> Результат с v4.3.3: <input disabled/>

Подробнее об изменениях в описании к релизу: https://github.com/bem/bem-xjst/releases/tag/v4.3.3

elemMods вместе с block вместо mods

В 5.0.0 был исправлен баг который приводил к неверному трактованию полей mods и elemMods. Подробности есть в описании релиза. Сейчас если вы попытаетесь передать в BEMJSON что-то типа { block: 'b', elemMods: { … } }, то получите warning.

Изменения this.ctx.mods через шаблоны

Такие фокусы будут награждены предупреждением, потому что хороший шаблон не должен иметь сайдэффектов, и не должен изменять входной узел BEMJSON-а. Чтобы изменить модификаторы вы должны использовать this.mods.

Атрибуты class или data-bem созданные через BEMJSON-поле attrs или шаблон режима attrs()

Для генерации HTML-класса используйте режим cls(). Для генерации параметров для клиентского JS используйте режим js(). Иначе будет вываливаться предупреждение.

Проверки нейминга

Имена блоков, элементов, модификаторов, а так же значения модификаторов не должны содержать разделителей имени элемента (обычно это __) и разделителей модификаторов (_).

Миксы модификаторов к таким же модификаторам

Всевозможная акробатика вида { block: 'b', mix: [ { mods: { type: 'test' } }, { mods: { type: 'shmest' } } ] }, будет награждена предупреждением.


Если у вас есть идеи какие проверки можно добавить еще — пишите мне. Спасибо.

Продолжение следует.

Настоящим постом хочу продемонстрировать вам как будет выглядет API bem-xjst v8.x. Все пока на стадии RC, поэтому хочу выслушать ваше мнение по поводу всего этого.

Изменения, которые войдут в v8.x

  • Все режимы теперь ведут себя одинаково: переопределяют значение из BEMJSON. (major)
  • Добавлены недостающие режимы: mods() и elemMods() для установки модификаторов. (minor)
  • Добавлены шорткаты режимов для добавления: addMix(), addAttrs(), addMods(), addElemMods(), addJs(). (minor)
  • Добавлены шорткаты для добавления content: appendContent() и prependContent(). (minor)

TLDR; Песочница bem-xjst v8.x RC: https://goo.gl/ZeY4xL, в которой можно попробовать все эти вкусности…

Технические подробности

1. Все режимы теперь ведут себя одинаково: переопределяют значение из BEMJSON. (major)

Сейчас значение из шаблона режима content(), bem(), cls(), tag() переопределяет значение указанное в BEMJSON. Если вам нужно расширить значение из BEMJSON в шаблоне нужно использовать applyNext() и this.extend()/concat().

Однако режимы mix(), js(), attrs() сейчас расширяют значение из BEMJSON.

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

В v8.x мы привели все режимы к одинаковому явному поведению: переопределение значения из BEMJSON. Если вам нужно добавить что-либо, то теперь это можно будет сделать в явном виде — см п.3.

2. Добавлены недостающие режимы: mods() и elemMods() для установки модификаторов. (minor)

Под капотом эти режимы просто шорткаты к уже привычным всем конструкциям:

// mods()({something: myValue})
def()(function() {
    this.mods = {something: myValue};
    return applyNext();
});

и

// elemMods()({something: myValue})
def()(function() {
    this.elemMods = {something: myValue};
    return applyNext();
});

Как видно из примеров режимы mods() и elemMods() не имеют своей собственно очереди шаблонов, а добавляют шаблоны в стек к режиму def().

По умолчанию mods() и elemMods() возвратят вам значения из this.mods и this.elemMods соответственно.

Пример:

// BEMJSON
{ block: 'b' }

//Шаблоны
block('b').def()(function() {
  return JSON.stringify(apply('mods'));
});

//Результатом будет:
[]

3. Добавлены шорткаты режимов для добавления: addMix(), addAttrs(), addMods(), addElemMods(), addJs().

Так как все режимы теперь переопределяют значение, то чтобы компенсировать необходимость писать applyNext() для накапливания результата были введены шорткаты для уже существующих режимов add*().

Под капотом addJs()({ somekey: someval }) это

js()(function() {
  return this.extend(applyNext(), { somekey: someval });
});

Под капотом addMix()({block: 'mixed' }) это

mix()(function() {
  var res = applyNext();
  if (!Array.isArray(res)) res = [ res ];

  return res.push({block: 'mixed' })
})

Для остальных режимов аналогично. Как видно из примера шорткаты add*() не имеют своего стека шаблонов, а просто добавляют шаблон в стек соответствующего режима.

И, естественно, вы можете накапливать результат:

// Шаблоны
block('b')(
   addJs()({ a: 1 })
   addJs()({ b: 2 })
   addJs()({ c: 3 })
);

// BEMJSON
{ block: 'b' }

// Результат:
<div class="b b_type_awesome i-bem" data-bem='{"b":{"a":1,"b":2,"c":3}}'></div>

4. Добавлены шорткаты для добавления content: appendContent() и prependContent().

// Шаблоны:
block('b')(
    appendContent()(', templates!'),
    appendContent()('!!1'),
    prependContent()('(〜 ̄▽ ̄)〜 ')
);

// BEMJSON
{ block: 'b', content: 'Hello' }

// Результат:
<div class="b">(〜 ̄▽ ̄)〜 Hello, templates!!!1</div>

Как вы уже наверное догадались, это тоже шорткаты и они добавляют шаблоны в стек режима content(). Пример:

// appendContent()(', templates!') это тоже самое что и:
content()(function() {
  return [
    applyNext(),
    ', templates!'
  ];
});

Привет. Начал использовать full-bem-stack ибо удобно. Столкнулся с не пониманием уровня детализации и инкапсуляции блока. Скажем, есть у нас стандартный слайдер со слайдами. .b-slider, .-b-slider__slide Каждый слайд состоит из картинки, фонового цвета, заголовка, текста и кнопки.

Как будет правильно создать блок слайдера?

{ 
    block: 'slider', 
    content: [ 
        { 
            elem: 'slide', 
            content: /* здесь выносим все элементы типа slider__slide-title, slider__slide-img т так далее */ 
        } 
    ]
} ```

или лучше для каждого элемента .b-slider__slide задавать аттрибуты, которые дальше превращать в нужную структуру элементов в шаблонизаторе bemhtml ?

P.S. Как в редакторе добавит код в <code> ?

Как можно реализовать вот такой прилипающий footer Ryan Fait's HTML5 CSS Sticky Footer на БЭМ?
Проблема в том, что блок должен обернуть содержимое body в тэг-обёртку и кроме того добавить определённые стили в и , что насколько я понимаю противоречит принципу независимости блоков. Можно вроде как добавить в и миксы, но как-то это на мой взгляд не совсем красиво ... да и насчёт миксов не уверен - недостаточно компетентен в БЭМ - методологии.

Собственно, уже не в первый раз возникает проблема, когда на одном узле нужно разместить несколько сущностей: несколько элементов, несколько блоков и т.д. Это абсолютно не противоречит концепции BEM и называется миксами. Но когда доходит дело до реализации, получается, что миксуемые сущности не отрабатывают свои шаблоны bemtree и bemhtml, а только добавляют свои классы. Считаю такое поведение шаблонизатором некорректным, т.к. каждый блок имеет право на самореализацию, даже если он - всего лишь миксин. Для примера, попробуйте скомпилировать это: nav__item link popup tag Это - элемент списка, который отображается в виде тега, является ссылкой, а при наведении, появляется тултип с подсказкой. Пример, конечно не ахти, но суть в том, что такая ситуация возникнуть может. Сейчас я это решаю, разнося сущности по разным узлам, увеличивая вложенность, но мне очень не нравится этот способ, т.к. является костылем, который можно не всегда применять, влияет на структуру документа.

Понятно что технология нужна. Но, нужна ли для этого отдельная технология? Например, на одном проекте у реализована двупроходная шаблонизация средствами bh. И все норм. Не проще ли добавить в bemhtml метод для генерации bemjson? И генерировать 2 набора шаблонов. Это избавило бы от нужды тянуть на клиент лишний инстанс bem-xjst.

Правильно ли я понимаю, что нельзя сматчиться на элемент блока, который примиксован к другому блоку?

// bemjson
({
    block: 'start-screen',
    content: [
        {
            block: 'button',
            mix: {block: 'start-screen', elem: 'button'}
        },
    ]
});

// bemhtml
block('start-screen')(
    elem('button').tag()('p')
);

Выдает такой html

<div class="start-screen">
    <div class="button start-screen__button"></div>
</div>

То есть правило в bemhtml не заматчилось. Ссылка на песочницу https://bem.github.io/bem-xjst/?bemhtml=block(%27start-screen%27)(%0D%0A%20%20%20%20elem(%27button%27).tag()(%27p%27)%0D%0A)%3B&bemjson=(%7B%0A%20%20%20%20block%3A%20%27start-screen%27%2C%0A%20%20%20%20content%3A%20%5B%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20block%3A%20%27button%27%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20mix%3A%20%7Bblock%3A%20%27start-screen%27%2C%20elem%3A%20%27button%27%7D%0A%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%5D%0A%7D)%3B%0A

Как сделать, чтобы в ошибки из бандла валились в консоль с указанием информации о блоке? Кроме как вручную писать try { } catch (e) { console.log(this.block, e) }

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

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

Суть - проекты собираются при помощи gulp. Html в них собирается используя gulp-file-include простейшими конструкциями вида:

@@include("../common/head.html", { "title": "Заголовок этой страницы" })

И на выходе несколько статичных страничек, немного отличающихся друг от друга. Ну как обычно в общем.

И все это меня вполне устраивает, я не хочу переходить пока полностью на бэм-стек, а начать с чего-то проще. Собственно, хотелось бы описывать шаблоны через bemjson, bemhtml (bem-xjst?). Чтобы на выходе получались статичные html страницы. Без привязки к js, без i-bem, просто статика html.

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