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-tools
match(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; })