Open 4ok opened 10 years ago
Насколько я понимаю, elemMatch
добавляет дополнительные предикаты к предикатам про элемент и когда там оказывается пусто, то этот матчер в результате отрабатывает как на все элементы, так и на сам блок. И т.к. в контексте блока this.ctx.elem
оказывается undefined
, блок content
так и остается div
-ом.
Судить баг ли это не возьмусь. Призываю @veged.
А чтобы прямо сейчас заработало как ожидается, можно написать, например, так
block('content')(
tag()('article'),
elemMatch(function() { return this.ctx.elem; })(
tag()(function() {
return this.elem;
})
)
);
багом можно считать тот факт, что на пустой elemMatch
никто не ругается — можно завести issue в bem-xjst
А как правильно составить шаблон, после того как поправят баг? Я думаю понятно, что я хотел получить в итоге
правильный шаблон уже написал @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
пришла строка или массив?
({
block: 'something', // typeof this.ctx === 'object' ?
content: [ // typeof this.ctx === 'array' ?
'Hello World!' // typeof this.ctx === 'string' ?
]
})
/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)
, a match(function () { return thix.ctx; })
Никак не пойму, почему не отрабатывает этот шаблон, а конкретно не подхватывает
tag()('article')
, если убрать из шаблонаelemMatch()
то тэг проставляется