Предлагаю способ решения проблемы коллизий имён блоков. Возникнуть такая ситуация может когда нам нужно использоть несколько библиотек, в каждой из которых есть блоки с одинаковым названием (но разные по реализации) и нам нужно использовать либо какой-то один из них, либо оба этих блока как 2 абсолютно разных.
Предлагаю для этого использовать алиасы, задавать которые можно будет в конфигах уровней переопределения, там где сейчас подключаются другие уровни переопределения (напр. в desktop.bundles / .bem / level.js ).
И конечно же пример: у нас есть библиотека с красивой большой кнопкой, которую надо использовать в нескольких особенных случаях для сайта, для всех остальных случаев мы хотим использовать кнопку из bem-controls. Тогда при настройке бандла мы укажем алисы для каждой из них, синтаксис может выглядеть примерно так:
exports.getConfig=function() {
returnBEM.util.extend(this.__base()||{},{
bundleBuildLevels:this.resolvePaths([
'../../bem-bl/blocks-common',
'../../bem-bl/blocks-desktop',
{
path: 'amazing-controls/desktop.blocks',
aliases: [
{ 'name' : 'button', 'as' : 'b-amazing-button' }
]
},
{
path: 'bem-controls/desktop.blocks',
aliases: [
{ 'name' : 'button', 'as' : 'b-ya-button' }
]
},
'../../desktop.blocks'
])
}) ;
};
Но как быть если имя блока есть в документации? Склеивается из частей в js?
Прошу прощения, но не понял вопроса... документация это просто одна из технологий блока (md/wiki)? Что склеивается в js?
кто-то из небожителей был категорически против именования пространств, но если при подключении блоков виртуально именовать их пространства через какой-то символ через те же алиасы — было бы удобно.
а вообще идея норм, только смущает:
aliases: [
{ 'name' : 'button', 'as' : 'b-amazing-button' },
{ 'name' : 'button', 'as' : 'b-amazing-button-1' },
{ 'name' : 'button', 'as' : 'b-amazing-button-2' }
]
Может быть лучше так?:
aliases: {
'button': 'b-amazing-button',
'logo': ['b-amazing-logo', 'b-another-still-amazing-logo']
}
или так:
path: 'bem-chototam/some.blocks',
prefix: 'chototam',
или так:
path: 'bem-chototam/some.blocks',
aliases: { // или extensions|overrides, скорее
'b-button': { // перегрузка параметров по умолчанию
'name': 'b-ya-button',
'mods': ...,
},
}
Тогда получается, что в контексте каждой библиотеки блоков имена последних должны быть уникальны, что логично.
И, опять же, документация должна генерироваться тоже не более чем для библиотеки блоков, но никак не бандла проекта. Тоже, вроде как, логично.
Нравится последний вариант, он самый гибкий, даёт возможность переопределить не только имя блока но и его элементов и модификаторов, а такое тоже может понадобиться.
Это товарищ пруф.
интереснее как это будет работать, а не синтаксические изыски.
Да, я сомневался: он ли
В общем, идею алиасов поддерживаю, последний вариант — да, самый гибкий, но надо подумать, какова сложность такой доработки. Весьма вероятно, что вообще все это в любом виде технически очень сложно или практически невозможно.
если в js коде используются i-bem абстракции, а не прямые вызовы jQuery, то почему нет?
Тут вопрос не синтаксический, а идеологический, скорее. Разные структуры дают разные возможности.
Проект (слой А) использует 2 библиотеки (B, D), первая (B) использует еще одну библиотеку (C).
А в принципе ничего не должен знать про C (инкапсуляция же), в то время как B не должен знать про A, но должен знать про C, и C ни про кого вообще не знает.
B будет использовать button, который прописан, виден по умолчанию (свой или, при отсутствии, из C), равно как и D.
Предположим, что в D button есть, а в B нет и она использует button из C, тогда в A с алиасом будем иметь:
amazing-button -> C.button
button -> D.button
В документацию, соотв., попадут все видимые блоки слоя (со всех уровней, получается).
Или я не правильно понял инкапсуляцию по БЭМ?
p.s. Хотя на счет D.button я не знаю, почему имеено D, а не B. Если ищем с конца и D подключен последней, то button действительно должен доставаться из D, иначе — не факт.
bem-* сплошь и рядом использует связывание по имени -- эта техника проста, доступна и весьма эффективна. с другой стороны -- она крайне плохо поддается контролю и рефакторингу -- коллизии имен это самое страшное, что только может случиться. поэтому абсолютно точно, с этим нужно что-то делать, чтобы их вероятность сводилась к нулю.
Блонд поднял важную тему. если не принимать вообще ни каких мер, то в условиях глобального пространства имен и достаточно узкой предметной области с ограниченным лексиконом, коллизии будут случатся достаточно часто, и я сомневаюсь, что библиотеки bem-компонетнов в таких условиях станут расширятся наружу, а не останутся проектом одной команды. вряд-ли алиасы могут быть реализованы технически. но этот пример, как минимум, показывает, что разработчикам библиотек bem-блоков о недопущении конфликтов имен нужно нужно думать заранее и использовать префиксы -- ведь ни какого механизма разрешения конфликтов имен сейчас нет, и в ближайшее время, не предвидится.
в текущей реализации бандлов есть одна большая ацкая кастрюля bundleBuildLevels, где смешивается код с разных уровней переопределения. кажется, что осмысленный результат, с большой степенью вероятности, может получаться лишь из кода, взятого с уровней переопределения, относящихся к одной библиотеке. т.к. лишь в контексте отдельной библиотеки код целиком контролируется разработчиками, и можно рассчитывать на адекватность рецептуры. при смешивании одноименного кода из разных библиотек, в результате чаще (т.е. практически всегда) получается чертов винегрет.
имхо, попадание в бандл одноименного кода, относящегося к разным библиотекам, это вероятнее всего нежелательное стечение обстоятельств, нежели осознанный кретив. было бы круто, если бы bem make как-то предупреждал об этом верстальщика. либо где-то (скажем в deps.js) можно было указывать не только "что", но и "откуда" должно импортироваться, чтобы оно импортировалось только откуда нужно, а откуда не нужно не импортировалось.
Никакой инкапсуляции сделать невозможно, потому что в CSS нативно её нет.
Разве это нерешаемые задачи? Да, этого не нативно, но и блоков в css нет нативно. При чем тут нативный css?
Тут рассматривается как раз такая ситуация, когда два разных блока из разных подключенных библиотек претендуют на одно название. И речь идет о варианте решения этой проблемы через алиасы.
Можно ещё немного развить последний вариант, на случай, когда нужно выпилить реализацию блока или его части.
path: 'bem-chototam/some.blocks',
aliases: {
'b-button': undefined, //исключает блок из бандла,
'b-checkbox': {
'elem': undefined //исключает элемент блок из бандла,
},
}
Да, конечно. Только тогда точно не aliases
Согласен, что при отсутсвии пространств имён следует подключать не целыми уровнями переопределения, а выборочно, только то, что нужно: это выглядит более безопасно.
Если уровень переопределения amazing-controls/desktop.blocks использует другой уровень переопределения в котором есть button, то при подключении всей этой машны в результирующий бандл обе кнопки должны переименоваться.
Хотя, если честно, я не понимаю зачем в *.blocks понадобиться подключать другие уровни переопределений, помоему, это только прерогатива бандлаов.
не вопрос
хм. видимо написал много текста. вот меры, которые я предлагю:
1. в библиотеках, использовать префиксы обязательно.
2. пересечение имен блоков из разных библиотек - баг, а не фича. об этом нужно предупреждать верстальщика.
Чтобы проще было понять как это должно работать, можно провести аналогию с реляционными БД, когда мы хотим соединить 2 таблицы, в которых называния полей могут совпадать: по сути мы попарно join-им таблицы, и можем каким-то полям задать алиасы.
пример
Есть таблицы A{ f3, f4 }, B{ f2 }, С{ button }, D{ button }.
Соединяем B и С, получаем временную таблицу BC{ button, f2 }.
Соединяем A и BC, делаем алиас (С.f1 as b-amazing-button) получаем временную таблицу ABC{ b-amazing-button, f2, f3, f4 }.
Соединяем ABC и D, получаем ABCD{ button, b-amazing-button, f2, f3, f4 }.
Может оказаться так, что в блоке который не надо переименовать, а в другом из его уровня переопределения написано, например this.findBlockInside('имя -блока-который-надо-переи меновать'). Хоть и в i-bem абстракции но всё равно поламается.
Тогда тут всплывает другая проблема, которая ещё тоже не решена - rename block/elem/mod/elemMod. Если её решить, невижу никаких проблем в реализации хоть алиасов, хоть пространств имён, хоть ещё чего.
Можно пример когда может понадобиться такое?
Ещё можно в одном блоке написать css-каскад другого блока. Когда переименуем 2й блок, в 1м каскаде не переименутся, и реализация так же сломается.
Да, аналогия неплохая. Полностью согласен с тем, что button должен быть из D, но по факту в коде может быть что-то вроде blocks[block.name] = blocks[block.name] || block;, и тогда в выборку попадет блок из C, т.е. библиотеки, подключенной раньше.
БЭМ, он же ведь, не о том как написать стили, он выше всей этой низкоуровневой нативщины, разве нет?
... вендерные префиксы и БЭМ-консорциум
Если использовать префикс bem-button, то в Лего будет часть блоков с bem- префиксом, а часть с lego- префиксом (те, которых нет в bem-controls), что нехорошо, на мой взгляд. Лучше без префиксов.
Но необходимость алиасов я понимаю. Их будет легко рализовать, если будет сделан bem mv.
если в lego-controls переопределяются блоки из bem-controls (т.е. меняя реализацию без порождения новых БЭМ-сущностей), оригинальные префиксы лучше сохранять - ведь речь по-прежнему будет идти об одном и том же блоке.
а можно не заниматься трепанацией и прикручивать нужное оформление сбоку, порождая новые БЭМ сущности через миксы/наследование/bridge или что еще придет в голову. в этом случае префиксы конечно стоит поменять -- bem-*'у бэмово, а lego-* - легово.