Во времена React.js и подобных вещей хочется и в bem.js чего то подобного.
Из дискуссии https://ru.bem.info/forum/385/ ничего внятного не вышло. Предлагаю вариант своей идеи как это можно сделать.
Основная идея
По аналогии с React
оперировать виртуальным деревом, но не в терминах DOM
а в терминах БЭМ
.
При загрузке страницы вместе с базовым HTML телом страницы отдается bemjson
и скомпилированный bemtree
или bemhtml
.
Создается виртуальное БЭМ дерево, далее из него формируется html
и рендерится на страницу.
Пример
На текущий момент bem.js
оперирует DOM
нодами посредством jQuery
.
Нужна реализация оперирующая БЭМ деревом (по факту развернутый bemjson) и обновляющая данные на странице при его изменении.
Скажем браузеру отдается страница вида
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<title>Hello</title>
</head>
<body class="page" bem-json="....">
// тут может быть отрендереный на сервере bemjson
</body>
</html>
Сам bemjson
имеет вид
{
block: 'comment-box',
js: {
url: 'comments.json',
pollInterval: 2000
},
content: [
{
block: 'comment-list',
content: [
{
author: 'Pete Hunt',
content: 'This is one comment'
},
{
author: 'Jordan Walke',
content: 'This is *another* comment'
}
]
}
]
}
Ну и сами блоки
JSONBEMDOM.decl('comment-box', {
onSetMod: {
js: {
inited: function() {
// метод findBlockInside спускается по нашему виртуальному БЭМ дереву
// и пытается найти bemjson блок comment-form
this.form = this.findBlockInside('comment-form');
this.commentsList = this.findBlockInside('comment-list');
this.form.on('submit', this._submitHandler);
this._loadCommentsFromServer();
setInterval(this._loadCommentsFromServer, this.params.pollInterval);
}
}
},
getDefaultParams: function() {
return {
data: [],
url: '',
pollInterval: null
}
},
_loadCommentsFromServer: function() {
$.getJson(this.params.url).done(function(comments) {
/**
* метод content() ожидает аргумент в синтаксисе bemjson
* который он применяет к `content` параметру блока в виртуальном БЭМ дереве
*/
this.commentsList.content(comments);
}.bind(this));
},
_submitHandler: function(e) {
e.preventDefault();
/**
* метод content() без аргументов отдает из дерева
* параметр `content` элемента, если это инпут то его значение
*/
var text = this.elem('text').content();
var author = this.elem('author').content();
$.post(this.params.url, {
text: text,
author: author
}).done(function (comment) {
var comments = this.commentsList.content();
comments = comments.concat([comment]);
this.commentsList.content(comments);
}.bind(this));
}
});
bem.js
сам отслеживает изменения в виртуальном БЭМ дереве, делает слепок отличий, накладывает на него bemhtml/bemtree
и инъектит его в текущий html.
В итоге мы имеем на клиенте
- Всю мощь декларативной шаблонизации
bemhtml/bemtree
- Красивый и структурированный
bemjson
на клиенте - Производительность из-за виртуального БЭМ дерева.
Спасибо что написал это. Давно думаю ровно тоже самое, но чего-то не хватало чтобы всё это красиво и грамотно сформулировать.
сс @tadatuta @veged @zxqfox
@JiLiZART А где код посмотреть?
Последний раз, когда мы это обсуждали, @veged предложил код сделать #385
@zxqfox ты просто делал акцент на immutable не расскрыв полностью идею с БЭМ-деревом на клиенте. Мне кажется у @JiLiZART получилось доступнее мысль передать в этом посте.
cc @dfilatov @narqo
@zxqfox мой уровень компетенции не позволяет мне реализовать хоть мало мальски рабочий прототип, т.к не имею знаний по части виртуального дома и как его можно реализовать.
@JiLiZART
<body class="page" bem-json="....">
— тут можно обойтись без bem-json, потому что есть шаблоны (информация о сущностях), и data-bem. Можно восстановить из data-bem атрибутов, как это и сейчас происходит.JSONBEMDOM.decl('comment-box', {
— всякое такое сильно поменяется, потому чтоi-bem.js
заточен под работу исключительно с бэм-сущностями в js реализации, и ничего не знает про render (BEMDOM.update(tpl.apply(newbemjson))
).Но переделывать ли
i-bem.js
, чтобы он внутри хранил virtualbem, делать ли что-то рядом — пока не понятно.В любом случае, если смотреть на React, то нужны какие-то такие персистентные структуры https://github.com/facebook/immutable-js — их сложнее хранить, но проще сравнивать при перерисовке. И в сумме рендеринг получается быстрее при мелких изменениях в разных мелких блоках, и жрет меньше памяти.
@Guria Я просто немножко покапался и предложил сразу как именно это можно сделать. Но этого все равно было недостаточно ;-) В любом случае, это сейчас нельзя сделать еще и потому, что BH/BEMHTML не умеют генерировать DOM-элементы. У них на выходе только строки.
Подпишусь
Извините, а тут правда все считают что если переписать на виртуальный дом то все сразу ух как полетит?
On 11 June 2015 at 10:38, Ivan Voischev notifications@github.com wrote:
@Yeti-or виртуальный дом позволит вычислить необходимый минимум операций над реальным домом для изменения. Что теоретически быстрее. А полетит, это уже от конкретной ситуации зависит.
@Yeti-or не готов говорить за производительность, но удобство разработки должно увеличиться однозначно. Мы получим возможность воспроизводить любое состояние интерфейса, а не только выполнять первоначальную шаблонизацию.
В целом, КМК, для текущего стека БЭМ больше подойдёт решение с immutable хранилищем состояния, на изменения которого подписаны заинтересованные блоки, которые, в свою очередь, сами кастомно перерисовывают то, что нужно, основываясь на понимании разницы нового состояния и текущего своего.
Блок будет похоже на redux, только сильно проще за счет того, что i-bem и так позволяет иметь блок-синглтон, общение с которым построены на событиях.
Таким образом, этот блок будет триггерить immutable состояния. Изменения состояния этого блока тоже будут реализованы событиями по типу actions в flux.
JFYI, https://github.com/bem-contrib/bem-flux
@tadatuta о, интересно) Правда, мне больше нравится подход с единым store. Тогда этот код можно упростить в разы.
@DimitryDushkin давай попробуем сделать
bem-cerebral
илиcerebral-view-ibem
http://cerebraljs.com@Guria офигеть, чего только не придумают)
Да, cerebral — интересный. Но я бы не стал его прям вот так прикручивать к БЭМу, она кажется избыточным: модули у нас и так есть благодаря депсам, роутинг = bem-history, и он еще похоже es2015 only.
У меня тут в задачах встретился хороший пример, в котором будет заметен профит от этих все наворотов. В ближайшее время попробую его переписать на что-то cerebral-redux-flux подобное. Тогда будет понятнее, чего в итоге хочется.)
На самом деле задачка про единый стор кажется тривиальной. Могу попробовать накидать пример на досуге. Можно сделать обертку над redux или через middleware транслировать bemjson на компоненты.
Привет!
Есть такой вариант использования redux в БЭМ-проекте: https://github.com/rakchaev/bem-redux Todo пример: https://github.com/rakchaev/bem-redux-todo-example
Концепцию, описанную в этом issue, поддерживаю, мысли давно похожие. С учетом увеличения клиентской логики на проектах, кажется, что уже пора абстрагироваться от низкоуровневой работы с DOM.
Предлагаю обсудить такой подход: https://github.com/rakchaev/j-bem.
Хех, я тоже недавно сделал flux (redux) на БЭМе — http://sky2high.net/2016/03/flux_i-bem/ Помимо i-bem подключил только immutable.js, чтобы не заморачиваться с ручным изменением store. Впрочем работа с DOM там как обычно.
j-bem looks fine. Думаю, может http://www.diffhtml.org/ или https://github.com/patrick-steele-idem/morphdom помочь делать дифф между результатами шаблонизации. Правда, тогда еще надо написать логику повторной инициализации блоков при необходимости.
@rakchaev кажется мы совсем о разном)
@DimitryDushkin спасибо,
bem-store
интересен! Кстати, если использовать модульную систему, то для создания единого стора можно не использоватьBEM
и другие конструкцииi-bem
вообще, так как нет завязки на блоки, а сразу провайдить стор в виде модуля. Добавил описание такого подхода на https://github.com/rakchaev/bem-redux.@awinogradov а вы про что?) я отдельно про подход обновления DOM "на лету" фреймворком и использования в качестве view-данных
bemjson
(основная идея issue) и отдельно проredux
, как подход к хранению данных в клиентском приложении. Вы хотите их вместе?@rakchaev ты не можешь независимо от
i-bem
обновлять DOM. Вернее можешь, но это будет каша. Кроме того ты не можешь его обновлять, используя шаблоны. Так как не умеешь их рендерить в виртуал. Кусок рассуждения есть тут https://github.com/bem/bem-forum-content-ru/issues/904. Сredux
илиflux
никаких нет проблем и вопросов, они не связаны ни с фреймворком ни с кодом реализации, вариантов сделать миллиард. Но кажется, что если хочеться жить вi-bem
, то надо расширять его функционал методами получения стейта. Так чтобы каждый блок во время инита получал стейт.@awinogradov Обновлять DOM конечно должен фреймворк. Ему нужно только передать знание о шаблонизации bemjson -> virtual-dom. Фреймворк отслеживает изменения в
bemjson
, применяет шаблонизацию на изменный кусок, строит дифф, применяет патч на DOM. См. пример https://github.com/rakchaev/j-bem.Шаблонизаторов bemjson -> virtual-dom пока нет, да. Но это вне зоны ответственности фреймворка.
Подходы вроде
redux
, кажется, относятся к уровню данных, а не view. Т.е. поверх механизма фреймворка, который умеет обновлять DOM "на лету", можно добавить хранение данных и логику изменения view (в нашем случаеbemjson
) черезredux
, если это нужно приложению. А можно не добавлять. Точно также как можно юзатьreact
безredux
, а можно с ним.То есть обновлять дом должен фреймворк, которого пока нет?
Sent from my iPhone
Да, мы же концепты обсуждаем :) Есть шанс, что по результатам обсуждений удастся инициировать доработки
i-bem
или реализацию нового, если мы к чему-то придем.cc @veged
@rakchaev так я решение рассказал в #904, над которым работаю:) Уже не концепт. Я думаю, что при наличии bemhtml->virtual Dom и bemjson=state в redux,
i-bem
перестанет быть нужен. Потому что он реализует апи для работы с блоками. Поиска, вставки и тд. + событийную модель. Все это не нужно, потому что принцип работы будет совершенно иной.Антон, спасибо, идею понял!
i-bem
хорош своей декларативностью. Логика/поведение всех сущностей описывается декларативно и изолировано. Как и в остальных технологиях реализации БЭМ-сущностей. Сbemjson
какstate
вredux
все кажется более глобальным и свзяанным. Например, интересно где и как описывать редьюсеры приложения; верно ли что логика любого блока сможет поменять дерево вне себя (у родителей, в соседних ветках); и менять отображение можно, видимо, только через action'ы.Но посмотреть было бы круто, подход интересный.
Надеюсь скоро посмотрим;)
Разбираясь в теме, наткнулся на Marko (от eBay) — http://markojs.com/ Там реализовали прогрессивную шаблонизацию — отдаем шаблонизированный HTML частями по мере его готовности на сервере. Также там более эффективная по сравнению с React система обновления DOM засчет отсутствия virtual dom.
В общем, marko очень любопытен с точки зрения тех фич, которые хотелось бы видеть в развитии i-bem.