UPD
По результатам вторых суток исследований ясно, что не происходит вызов decl.fn.apply
в ymodules:startDeclResolving
, т.е., до вызова provide(...)
дело не доходит. Похоже, дело в том, что инициализируются те модули, что были определены до вызова jQuery.ready
.
modules.define
отрабатывает (кажется) нормально и описание модуля появляется в modulesStorage
. Т.е., в этой части вроде всё ок.
Т.е., как сейчас представляется, нужна возможность сказать (кому? YM?), что добавлены модули и надо бы проверить зависимости.
На данный момент проблема решилась ручным вызовом modules.require(['test1'], ...)
после загрузки кода модуля. Немножко странно, но работает. Видимо, если не найдётся более грамотного решения, буду лепить подпорку на основе этого хака. Увы.
Описание ситуации
Загружаю btmhtml-шаблоны и y-модуль с кодом класса блока динамически, примерно таким образом (упрощённо; специально вытащил в тапой отдельный код, чтоб проще отлавливать ошибки):
var src = '/static/js/bem-test/test.browser.js';
var script = document.createElement('script');
script.type = 'text/javascript';
script.charset = 'utf-8';
script.onload = function script_on_load () { console.info('test1 script loaded'); };
script.src = src;
var head = document.getElementsByTagName('head')[0];
head.appendChild(script);
Шаблоны подсасываются и работают нормально (с небольшим хаком в BEM-XJST User-code Start
), а вот с модулями какая-то беда.
I-BEM почему-то думает, что этот блок должен быть live
-- причём только при такой (динамической) загрузке; если цеплять линком (<script ... src="..."></script>
), то всё срабатывает нормально.
После загрузки модуля блок создаётся примерно так:
var pageBemhtml = { block : 'test', content : 'test1' };
var pageHtml = BEMHTML.apply(pageBemhtml);
var pageDom = BEMDOM.update(app.elem('container'), pageHtml);
В порядке эксперимента пробовал после этого ещё насильно инициализировать блок (с помощью BEMDOM.init(...)
), -- результат нулевой.
Было замечено, что в initBlock(...)
не выполняется условие
if(!(blockClass._liveInitable = !!blockClass._processLive()) || forceLive || params.live === false) {
-- и класс блока (block = new blockClass(uniqIdToDomElems[uniqId], params, !!forceLive);
) не создаётся.
В дебагере пробовал возвращать из _processLive()
false
, -- тогда проходит внутрь и вроде как создаёт blockClass
, но с live
та же засада. Пока не понял, куда смотреть, что ещё отваливается.
И главное -- совершенно не понятна причина отваливания.
Прошу подсказок и советов.
Исходники шаблонов и модуля (на всякий случай)
Код модуля (тут для примера всё максимально простое пока):
console.info( 'module test1 root code' );
modules.define('test1', [
'i-bem__dom',
'jquery',
],
function ( provide,
BEMDOM,
$
) {
console.info( 'module test1 provide' );
provide(BEMDOM.decl('test1', {
onSetMod : {
'js' : {
'inited' : function() {
console.info( 'module test1 initalize' );
}
}
},
}
));
});
И шаблон (bemhtml):
block('test1')(
content()(function(){
var ctx = this.ctx;
return [
'<h1>Test1</h1>',
ctx.content,
];
}),
js()(function(){
return { test : 'test1' };
})
);
Версии бибилиотек:
"bem-core": "~2.9.1",
"bem-components": "~2.5.1",
@lilliputten Уточните, когда прилетают модули, блок уже присутствует в DOM?
Нет, блок создаётся только после загрузки модуля.
По последним исследованиям (второй день пошёл:))) вроде бы похоже, что засада где-то в отработке зависимостей (в
ym/modules.js
). Пока не получается разобраться, что именно происходит: где-то вrequireDeps/applyRequires
и т.п. -- приходится искать наощупь/наугад.@lilliputten
Привет!
Накидал пример решения твоей задачи: https://github.com/bem/project-stub/compare/issues/1094?expand=1
Вся магия кроется в строке https://github.com/bem/project-stub/compare/issues/1094?expand=1#diff-08bf73238b359931686e0476614fb692R22, остальное — это просто попытка получить то, что ты описываешь.
@tadatuta О, как! Спасибо!
Тоже накидал пример (в issue на ymodules). Попробовал в своём коде вместо
require(<имя_модуля>, ...)
делать реквайр на'i-bem__dom_init'
-- тоже работает. Возможно, так и оставлю (удобней, -- по крайней мере, не надо индексировать все содержащиеся в пакете модули).С другой стороны, можно перенять способ загрузки шаблонов через
vow/loader
-- я-то оборачивал шаблоны в пакете в совершенно жуткую конструкцию, при этом взламывая ещё и сам BEMHTML.Единственный маленький минус -- зависимость от
modules.require('BEMHTML', ...
-- т.е., таким образом подготовленные шаблоны надо подключать уже строго после инициализации модульной системы.Тем не менее, видимо, перетащу всё на этот способ, как более простой и масштабируемый.
Буду разбираться.
Не обязательно. Можно загружать шаблоны просто как функцию в глобалскоупе и компилировать в момент, когда BEMHTML доступен. Вот коммит с примером: https://github.com/bem/project-stub/commit/79b99d09c38278ca2fc8a1af03bd4b8b39004079
@tadatuta Да, так ащё лучше. Я бы только ещё добавил, как у меня было: складывание шаблонов в очередь по мере загрузки и компиляцию уже всех накопленных (имеется в виду, что может загружаться несколько пакетов шаблонов сразу).
А что скажут уважаемые специалисты за рекомендованный способ подгрузки стилей по запросу?
loader
вроде бы не умеет. Видел, как поступаетloader_type_bundle
, но там как-то очень уж монструозно всё это реализовано (hcss -- мне показалось, что лучше уж громадным куском чистых стилей и без проверок сразу всё грузить, с возможными повторениями пытаясь бороться к.-то иными способами).Сейчас подгружаю нужные пакеты стилей с помощью банального
document.createElement('link')
-- естественно, без проверок содержимого и проверки успешности загрузки (как понял, это при таком подходе невозможно).Только следите, чтобы у вас от порядка загрузки шаблонов не менялось поведение. Оно может, если шаблоны написаны без учета, чтобы будут грузится в разном порядке.
@lilliputten Руками, конечно, подготавливать нужный для
loader_type_bundle
— это ад.Он рассчитан на использование вместе с https://github.com/enb/enb-bembundle/, но, к сожалению, мы все никак не соберемся переписать
enb-bembundle
под использование с модульной системой :(Впрочем, именно для стилей теоретически он может и взлететь, хотя я бы не поручился. А так-то формат максимально эффективный: за один HTTP-запрос можно загрузить нужные стили + скрипты + шаблоны.