block('content')
(
tag()('article'),
elemMatch()
(
tag()(this.ctx.elem)
)
);
Никак не пойму, почему не отрабатывает этот шаблон, а конкретно не подхватывает tag()('article'), если убрать из шаблона elemMatch() то тэг проставляется
Насколько я понимаю,
elemMatchдобавляет дополнительные предикаты к предикатам про элемент и когда там оказывается пусто, то этот матчер в результате отрабатывает как на все элементы, так и на сам блок. И т.к. в контексте блокаthis.ctx.elemоказываетсяundefined, блокcontentтак и остаетсяdiv-ом. Судить баг ли это не возьмусь. Призываю @veged.А чтобы прямо сейчас заработало как ожидается, можно написать, например, так
багом можно считать тот факт, что на пустой
elemMatchникто не ругается — можно завести issue в bem-xjstЗавел https://github.com/bem/bem-xjst/issues/18
А как правильно составить шаблон, после того как поправят баг? Я думаю понятно, что я хотел получить в итоге
правильный шаблон уже написал @tadatuta (если мы оба правильно поняли, что хотелось получить в итоге)
Спасибо, разобрался
У нас в доках везде примеры
match(this.ctx.something === 'something'), хотя это нужно оборачивать в функцию. ;-(в функцию нужно оборачивать, если предикат может иногда падать из-за
undefined— ноthis.ctxобеспечивается в самом базисе (https://github.com/bem/bem-core/blob/v2/common.blocks/i-bem/i-bem.bemhtml#L164), а вот предикаты типаthis.bla.blaнужно оборачивать, т.к.this.blaможет не бытьТолько что пытался собирать проект в
enb, который нормально собирался тулзами, иthis.ctxтам не всегда был объектом. В т.ч. он был и массивом, и undefined. Это баг? Посмотреть почему?да, давай разберёмся (лучше в отдельном тиките) — потому что я вот привёл исходники базовых шаблонов и вроде как оно всегда должно быть
@zxqfox предположу, что разница где-то в используемых версиях
bem-xjst.ENBилиbem-toolsсами по себе как-то влиять на шаблоны не должны.в случае
bem-toolsобычноbem-xjstпоставляется в виде npm-депендовbem-core, а при использованииENB— ставится на уровне проекта.Так. В
enbгенераторомbem-coreс зависимостью"enb-bemxjst": "1.2.0",, на уровне проекта та же версия. И"bem-xjst": "0.4.0",.В случае
bem-toolsта же версия, и ошибка при сборке не повторяется.копаю дальше.
@zxqfox еще могу предположить отличия на уровне технологии для сборки deps-ов. если для
ENBиспользуетсяdeps, можно попробовать перейти наdeps-old— это порт логики изbem-tools. пока других идей нет.@tadatuta а что вообще должно быть в
this.ctx, когда на входе изbemjson.jsвcontentпришла строка или массив?/cc @veged
@zxqfox Не уверен, что понимаю вопрос, но в
this.ctxрекурсивно падают узлы BEMJSON-дерева, дальше перебираются матчеры и выполняется тело сматчившегося шаблона.Т.е. в твоем примере при матче на
block('something')вthis.ctxокажется весь узел, который ты приводишь. При матче по модеcontent, вернется содержимоеthis.ctx.content, в приведенном примере это массив. Для него выполнится рекурсивныйapplyна каждый элемент (в этот момент вthis.ctxокажется строка), отработает матч наisSimple()и в буфер приплюсуется'Hello World!'.@tadatuta Да, вопрос был поставлен некорректно. Спасибо за подтверждение.
В общем, там кардинально отличаются сгенерированные
bemhtml.js. Вbem-toolsmatch(thix.ctx.type === 'something')превращается вif (__$ctx.ctx.type ..., вenbоно остается как есть, и поэтому валится.Если сделать так:
match(this.ctx && this.ctx.type === "something")(, или завернуть вfunction, то начинает отрабатывать и перестает валится. Считать ли это багом или нет — сложно сходу сказать, не понятно, как именно оно должно работать.Но факт остается фактом —
match(thix.ctx.type === 'something')вenbвалится, когда вthix.ctxпо какой-то причине приходитundefined. С тулзами такой проблемы нет.Весь разговор сводится к тому, что шаблонизатор работает не тревиально, отсюда куча вопросов
И вообще, elemMatch условие не должно попадать, когда this.ctx.elem пустой, а в приведеном шаблоне от @tadatuta это не так
@4ok ну как, если оборачивать условие соответствия в колбек — то контекст туда нормально передается, у меня проблема в том, что
this.ctx === undefined, и сам шаблон падает при запуске.т.е. в
elemMatch(условие)(инструкции)не пустое условие, как в твоем случае, а такое, что генерирует код, падающий при запуске. но только при сборке вenb.@zxqfox Леша, а уж не в том ли дело, что
bem-toolsв твоем случае компилируют шаблоны в продакшен-режиме, аENB— в дев?@tadatuta угу, есть и такая вероятность. Пишу тест для bem-xjst, надеюсь поймать ошибку.
Прод или дев, ведь не должно быть разницы, разве нет?
@4ok отличие в режимах сборки в том, что в дев-режиме шаблоны просто конкатенируются с кодом «ядра» и друг с другом, а в продакшен-режиме происходит компиляция исходного кода в более эффективный с точки зрения скорости выполнения.
в результате, как и написал @zxqfox, имеем следующую ситуацию: в продакшене
block('something').match(thix.ctx.type === 'something')превратится в (псевдокод)if(__$ctx.block === 'something' && __$ctx.type === 'something'), а в дев-режиме, как и должно быть в JS, сначала выполнится операцияthix.ctx.type === 'something', а потом ее результат будет передан вmatch(). т.е. это сравнение будет выполняться даже тогда, когда не выполняется матч наblock('something'), т.к. обрабатываетсяapply()на какой-то совсем другой узел.@tadatuta простите, не отписал, но дело в этом, да. Будем как-то что-то делать? Вообще, надо бы.
если вы хотите задать вопрос команде, то ставьте еще и метку asktheteam ;) спасибо!
https://github.com/zxqfox/bem-xjst/commit/c7aef30944893f57d54708ba7c97b711ef0d65c1 В общем, вот. Как чинить пока не знаю. При чем, валится как в продакшн, так и в дев режимах.
@zxqfox так мы специально сделали, чтобы все матчи, содержащие обращение к полям
thisтребовали анонимной функции — это гарантирует работоспособность шаблона в dev-режиме.@tadatuta тогда надо документацию поправить. но с анонимками будет сложно оптимизировать
@tadatuta ну и да, конкретно этот тест от флага оптимизации не меняет поведения и не перестает падать.
После обсуждений с @andrewblond и @veged выяснили, что надо обновить доку и синтаксис
match(this.ctx.something)зависит от базовых используемых блоков и лучше всегда кастомные вещи заворачивать в анонимную функцию. т.е. неmatch(this.ctx), amatch(function () { return thix.ctx; })