Open mathetes opened 8 years ago
@mathetes а почему заинтересовал bemtree именно из bem.info? Может больше ясности внесет этот проект? https://github.com/voischev/express-bemtree-project-stub
Вот что вам нужно: https://github.com/express-bem/project-stub
@voischev @zxqfox то, что вы предлагаете принципиально отличается от того, что у меня в bem.info. У меня генерируется статика, никакого экспресса там нет (и пока не планируется). При этом есть bemtree, генерирующий bemjson и очень простой bemhtml у каждого блока.
@mathetes в desktop.bundles/index надо смотреть только на index.bemdecl.js (его содержимое exports.blocks = [{ name: 'root' }];
, остальное генерируется в результате сборки через enb.
Покажите, что у вас сейчас получилось и что именно вызывает вопросы.
@vithar ну я не особо много вижу смысла в bemtree без сервера, есть же bemjson. По этому и предлагаю что могу)
Почему bemjson не достаточно в данном случае? Если только генерить контент например из .md
файлов... или подобное. Я бы сначала про задачи спросил)
@voischev я рассматриваю bemjson, как генерируемый формат. Не вижу ни одной причины хотеть писать его руками, кроме может простых промо-страниц.
Есть какие-то данные, какая-то структура за bemjson и вот с ней и надо работать, а bemjson это промежуточный формат, чтобы из него просто получать html. Основная логика у меня в bemtree, bemjson генерируется, шаблоны bemhtml получаются простыми.
Понятно что bemhtml простой) Понятно что если "есть какие-то данные" то лучше bemtree. И понятно что bemjson промежуточный :) и удобен только для простых задач.
Я лишь говорю что нужно понять)) — как минимум какой род этих каких то данных))) Ну ладно
@vithar Молодцы! Жаль что года 3 назад до этого не дотумкали ;-(
@zxqfox не знаю о чем именно 3 года назад не дотумкали, но коммит с open source реализацией BEMTREE наружу датируется маем 2013, а рассказы о трехзвенной архитектуре и необходимости генерировать BEMJSON были чуть ли не с момента первого анонса BEMHTML ;)
@tadatuta Не, я не про сам bemtree, я про:
У меня генерируется статика, никакого экспресса там нет (и пока не планируется). При этом есть bemtree, генерирующий bemjson и очень простой bemhtml у каждого блока.
Не представляю пока, что вы там за космолет сделали, но очень не хватало процессора для bemtree в рамках bem-tools/enb, чтобы без экспресса запускать и из raw data получать html, как это делают обычные шаблонизаторы ;-)
@zxqfox https://github.com/bem/project-stub/commit/5b07cc3a4020b509165cde6f8ba904f5a9341e78 — 14 ноября 2013 года
Отдельный стаб со статикой на BEMTREE я запаблишил почти год назад, правда не так часто его обновляю.
Не представляю пока, что вы там за космолет сделали
Ты так говоришь, как будто BEMTREE.apply(require('./path/to/data.json')).then(function(bemjson) { require('fs').writeFileSync('page.html', BEMHTML.apply(bemjson)); })
— это что-то космическое ;)
@tadatuta Может я не понимаю, но... Разве речь не о:
Хотя стоп, enb же не умеет динамические бандлы? Тогда вы там космос делаете.
Посмотрел ссылку, пойду плакать, все еще не то. Точнее, все еще не до конца то.
@zxqfox чего именно не хватает, чтобы было то?
@tadatuta В бандле пишу data.json и bemdecl, оно мне это отправляет в bemtree, ну и дальше по списку. Бекендеры не понимают bemjson ;-)
в чем отличие того, что по ссылке, от того, что ты хочешь?
Не то, чтобы я прям очень хочу, но было бы здорово иметь, потому что это снижает порог входа. По ссылке, как бы, хаки какие-то, но очень похоже, да.
@vithar У меня пока ничего нет. Как я понимаю мне нужно в desktop.bundles в файл index.bemtree.js декларировать блоки. Но в этом файле уже есть много других функций. В какой файл тогда и каким образом мне декларировать блоки?
@mathetes в desktop.bundles/index надо смотреть только на index.bemdecl.js (его содержимое exports.blocks = [{ name: 'root' }];
, остальное генерируется в результате сборки через enb.
Дальше надо смотреть в common.blocks/root/root.deps.js. А потом в соответствующие зависимости прописанные в этом блоке.
Каждый блок содержит реализацию себя на всех технологиях и указывает от чего зависит.
В common.blocks/root/root.deps.js продекларирован только один блок page где остальное? Можете сказать точно куда декларировать все блоки? Чтобы произошла генерация через enb надо сначала продекларировать эти блоки. Вот и вопрос в какой файл? Я пока нашел мало мануала по использованию bemtree Всего одна страница https://ru.bem.info/technology/bemtree/v2/bemtree/ И какие фрагменты в видеосеминарах.
Декларировать все блоки никуда не надо. В root.deps.js
написана зависимость от page
. В page.deps.js
написана зависимость от других блоков, у них от третих. enb собирает это всё, рекурсивно обрабатывая зависимости блоков.
bemtree как BEMHTML, но на выходе генерирует не строки, а объекты, содержащие bemjson. Синтаксис матчей такой же, смотрите у меня примеры, там всё понятно.
@vithar Хочу уточнить про реализацию в bem-info. Это main-stream как надо работать с bemtree через enb или специфика при работе с данным проектом использующим gulp? Могу ли я использовать данный подход при работе на основе generator-bem-stub? К сожалению пока не могу понять как работать с bemtree. По изученным мануалам нужно описать требуемые на странице блоки и они сгенерятся в bemjson. Еще раз прочитал мануал, который сразу извиняется за то, что не является инструкцией. Посмотрел файлы root.deps.js page.deps.js index.deps.js В них примерно одинаково как я называю "декларируются" различного уровня блоки. В index.deps.js большой список блоков, который вызываются при загрузка страницы index. Или опять не так?
Сергей Максимов video.yandex.ru/users/ya-events/view/2305/ представляет работу следующим образом декларируешь BemTree он генерит bemjson и выдает html. Это мне понятно. Причем тут еще deps.js не могу понять.
Я не знаю main-stream это или нет, и что вообще можно назвать main-stream'ом.
Я не хочу применять никакую динамику и хочу оставаться в рамках генерации статических файлов при разработке нового bem.info так долго, как это будет возможно. Если где-то будет нужна динамика — буду делать гибрид, когда часть страниц лежит статикой, а только то, что нужно — генерируется динамически. Например, форум точно будет динамическим, он статикой невозможен.
Давай я попробую подробно описать как это всё работает, может кому-то ещё пригодится.
За каждым сайтом стоят какие-то данные из которых нужно генерировать html конкретных страниц. Сайт состоит из страниц, у каждой страницы есть URL, title, и прочие атрибуты.
У меня эта структура описывается в content/pages.js
. На самом верхнем уровне идёт разделение по языкам (у меня это ru и en), дальше массив страниц. Каждая страница описывается объектом:
{
url: 'адрес страницы',
site: 'подсайт', // подсайты могут иметь другую навигацию или внешний вид
title: 'заголовок страницы',
source: 'где брать контент', // простая строка или
// путь к файлу (начинается с ./) или
// URL (начинается с http)',
type: 'тип контента' // md – если не указан, используется marked для конвертации в html)
// bemjson.js — используется как есть
// lib — специальный тип для библиотек, чтобы построить
// меню как на этой странице в шапке
// http://bem.harisov.name/platform/libs/bem-core/2.7.0/
}
Бандл у меня пока один, он лежит в desktop.bundles/index/
, файл, который пишется руками там один — desktop.bundles/index/index.bemdecl.js
, всё остальное генерируется в процессе сборки через enb
.
Его содержимое:
exports.blocks = [{ name: 'root' }];
Во время сборки enb
читает этот файл декларации страницы, видит в декларации один блок root
. Ищет блок root
на всех указанных в конфиге .enb/make.js
уровнях.
У меня это
levels = [
{ path: 'libs/bem-core/common.blocks', check: false },
{ path: 'libs/bem-core/desktop.blocks', check: false },
{ path: 'libs/bem-components/common.blocks', check: false },
{ path: 'libs/bem-components/desktop.blocks', check: false },
{ path: 'libs/bem-components/design/common.blocks', check: false },
{ path: 'libs/bem-components/design/desktop.blocks', check: false },
'common.blocks'
];
Релизация блоков лежит в common.blocks
, остальные уровни библиотечные и сейчас мы их не рассматриваем.
Итак, идём в common.blocks/root/root.deps.js
и видим, что этот блок зависит от i-bem
(лишняя зависимость, надо выкосить) и page
:
({
mustDeps : ['i-bem'],
shouldDeps : [
{ block : 'page' }
]
})
Идём в common.blocks/page/page.deps.js
и видим, что этот блок зависит от i-bem
(лишняя зависимость, надо выкосить) и блоков, которые являются корневыми на странице:
({
mustDeps : ['i-bem'],
shouldDeps : ['header', 'nav', 'promo-header', 'promo-main', 'article', 'footer']
})
Причём на странице может быть или promo-header
и promo-main
, или article
. Можно пойти дальше и разбить на два бандла (promo
и content
), но меня пока устраивает всё в одном, оптимизацию буду делать потом.
Дальше идём по очереди во все блоки, от которых зависит page
и ищем в них deps.js
-файлы.
В итоге строится файл desktop.bundles/index/index.deps.js
в котором находятся все зависимости всех блоков, необходимых для построения страницы.
Этот файл используется для поиска файлов реализации на всех уровнях переопределения для генерации файлов технологий css
, js
, bemhtml
, bemtree
. Эти файлы собираются и складываются desktop.bundles/index
.
С технологиями css
и js
блоков надеюсь всё понятно (если нет — спрашивай), теперь рассмотрим, что происходит в bemtree
и bemhtml
.
Вызов bemtree
происходит в gulpfile.js
в applyTemplates
:
var bemjson = bemtree.apply({
block: 'root',
data: {
page: page,
pages: pages[lang],
langs: langs,
lang: lang
}
});
На вход подаётся блок root
c данными в поле data
. В данных лежит page
— текущая страница из sitemap описанного выше, в pages
весь sitemap для текущего языка, в langs
и lang
соответственно массив всех языков и текущий язык.
К блоку root
применяется шаблон из common.blocks/root/root.bemtree
, там генерируется заголовок страницы в обратном порядке, подготавливаются данные по всем библиотекам и сохраняются в pages, потом генерируется блок page
.
К блоку page
применяется шаблон из common.blocks/page/page.bemtree
. Он возвращает массив из блоков header
, nav
, вставляет переданный bemjson или генерирует article
и footer
.
К ним тоже применяются соответствующие bemtree
-шаблоны.
После работы всех bemtree
-шаблонов возвращается финальное представление страницы в виде bemjson
.
Создаём в output
соответствующую странице директорию:
var dirName = outputFolder + lang + page.url;
fs.mkdirsSync(dirName);
К bemjson
применяем bemhtml
и сохраняем в файл index.html
соотвествующей директории:
fs.writeFile(dirName + '/index.html', bemhtml.apply(bemjson));
Это позволяет нам автоматически иметь красивые URLи без применения rewrite'ов.
Копируем в эту же директорию файлы из директории, где у нас лежат .md
файлы:
var source = page.source;
var type = page.type || 'md';
if (type === 'md' && /^\.\//.test(source)) {
var sourceDir = source.replace(/[^\/]*$/, '');
fs.copySync(sourceDir, dirName, { filter: function(file) { return !/md$/.test(file) }});
}
Это позволяет указывать в '.md' относительную ссылку на картинку:
![Декларация](build__declaration.png)
А потом так же относительно использовать её в .html
:
<img src="build__declaration.png" alt="Декларация">
bemhtml
шаблоны при этом получаются очень простые:
block('breadcrumbs')(
js()(true),
tag()('ul'),
elem('item').tag()('li')
);
Или чуть сложнее:
block('search')(
js()(true),
elem('switcher').content()(function() {
return require('fs').readFileSync('common.blocks/search/search__switcher.svg', 'utf8');
}),
elem('input')(
tag()('input'),
attrs()(function() {
var attrs = applyNext() || {};
attrs.name = 'text';
attrs.type = 'search';
attrs.autocomplete = 'off';
attrs.placeholder = this.ctx.placeholder
return attrs;
})
)
);
Но важно, что в bemhtml
находится только логика про генерацию html
, нет ничего про обработку данных, она на предыдущем слое в bemtree
.
Надеюсь стало понятнее. Если есть ещё вопросы — спрашивай.
Попробовал обобщить схему в посте https://ru.bem.info/forum/716/
Спасибо за подробное описание процесса. Очень нужно. Стало понятнее, но не до конца. Еще Владимир Гриненко сделал отдельный пост для меня. Его тоже штудирую. По поводу main-stream хотелось бы понять пример работы с БЭМ на фул-стэке. Каким образом определяется структура DOM дерева в процессе? То есть как определяется вложенность блоков у страницы? Как получается, что на bem.info один и тот же bundle генерит несколько страниц? Я думал тут динамическая генерация, оказывается статическая согласно вашего утверждения. Не понимаю тогда. Судя по последнему посту тут задействован pages.js. Продолжаю штудировать последний пост. Нужно время переварить все это. Еще раз спасибо за консультацию.
Пытаюсь разобраться с bemtree. Хотел бы использовать решения из bem.info для своего проекта. Скопировал нужные блоки в папку common.blocks. В папке desktop.bundles лежат файлы bemtree и html, но они выглядят как обычные js функции, а не как привычное описание блоков. Потом все это генерится в output-ru Как это использовать? Извиняюсь за бестолковые вопросы. Но больше спросить не у кого.