Конспект встречи Арикона с Лешей Ярошевичем
bem-tools 2.0 — это модульная штука, где ядро — это небольшая программа, использующая COA и для которой можно писать библиотеки.
Все, что относится к командам и АПИ реализуется в виде АПИ.
Уже сейчас с командами сделано, так, что команды можно расширять. Это сделано за счет COA.
Текущее АПИ нужно выносить в отдельные модули. Все команды реализуются в виде отдельных пакетов с экспортируемой функцией, которая на вход получает определенный контекст.
Но как писать эти команды? Копипастить код из текущих bem-tools плохо, т.к. будет много копипаста. Так что нужно вынести куда-то общебэмовую функциональность:
- bem-config, который умеет читать common-js модуль. Когда программе нужна какая-то настройка, она дергает функцию из конфига (у нее зовется коллбек).
- Уровни (bem-levels)
- чтение конфигов
- интроспеция
- создание уровня
- deps (bem-deps)
- stub
- parse
- Deps
- merge
- intersect
- substruct
Служебное низкоуровневое API (bem-util):
- map
- reduce
- translate
- create (new)
Build берет на вход декларацию (список) и технологию, а на выходе получается как правильно одна сущность — reduce (получает размеченный список сущности, у которых уже есть технология).
translate — это часть bem create, которая из одного файла технологии получает файл в новой технологии.
В bem-tools 2.0 хочется писать технологии не для команд bem create/ bem build, а технологии для сборки. Они будут работать по-разному в зависимости от необходимой собираемой технологии и вызывать внутри себя bem reduce, bem translate, etc.
bem-sets — это форк bem-pr, который отличается по интрефейсу, т.к. служебные библиотеки нужно подключать как npm-модули. Теперь bem-sets расширяются для сборки документации.
bem map — на входе несколько уровней и декларацию, а на выходе не одна сущность, а пачка значений. Пришедший набор в декларации возвращается таким же набором, но как-то трансформированным. Нарпимер, был были common.blocks + desktop.blocks и в результате examples собираются смерженными по специальным правилам.
taffyDB (?)
Пакет bem-tools по зависимостям тянет стандартные модули.
bem make будет отдельным пакетом.
@zxqfox: Я приведу ряд тезисов, которые надо подтвердить или опровергнуть/поправить.
Структура проектов в общем смысле фиксирована (bundles/bundle/blocks/block, blocks/block, etc.), за исключением **/.bem. Собираемые сущности: узел (бандл/блок), реализация технологии. Служебные сущности: уровень, технология. [понятия технологий несколько смешаны, говоря реализация я буду подразуменвать css, bemhtml, bemjson файлы самих блоков, говоря технология — уникальную алгоритмическую составляющую]. Любой проект — направленный граф из узлов и реализаций (далее граф проекта), описываемый в общем случае директорией узла и реализациями. Сборка любой цели работает с подграфом этого графа, получаемого путем несложного преобразования (map, filter, reduce, etc). Например, из графа проекта можно получить подграф для сборки реализации технологии X какого узла, граф из набора реализаций технологий [X,Y,Z], или граф блоков. Filter может выполняться в любом порядке; map, reduce должны выполняться по упорядоченному подграфу относительно цели. Граф проекта должен иметь возможность достраиваться асинхронно по требованию, чтобы не читать весь граф проекта при старте.
bem-tools — платформа для запуска модулей, работающих с bem предметной областью. bem-config — Конфигурация — peer-dep: bem-tools — модуль, предоставляющий API для работы с конфигурациями уровней. Умеет читать любые конфиги, возможно, будет уметь мержить конфиги, но не вдаваясь в подробности самих конфгиов. Т.е. тупой extend. bem-level — Уровень — peer-dep: bem-tools — хранит информацию об именовании и умеет получать плоские списки узлов, реализаций, технологий; предоставляет API для работы с информацией об уровнях.
Каждый уровень через функционал bem-tools провайдит какой-то доп. функционал, усложняет базовый объект BEM (или BEM.api), и подключаемый модуль может требовать какой-то функциональности. Т.е. модули зависят друг от друга, но работают через общий объект из bem-tools. Либо же асинхронно провайдят, как в ym.
Вроде бы, это самое базовое. Я правильно понимаю общую логику?
Открытые вопросы ;-)
С уровнями, в общем случае, какие-то проблемы есть, кроме перегретого интерфейса и расшаривания getConfig? Есть смысл строить граф проекта в рантайме и шарить между остальными пакетами? Или пусть этим исключительно bem-build занимается? Технологиям про это хорошо бы знать, хотя бы иметь возможность выбирать подграф для работы. Есть, наверное? С deps все как-то усложняется. Сейчас deps описывается и в блоках, и в pages, но нужно ли оно в общем случае? Какие задачи он сейчас решает? Если deps описывает зависимости, а bemdecl описывает используемые блоки, может ли одно из другого получаться путем прямого преобразования через reduce? И можно ли избавиться от mustDeps, shouldDeps, и, особенно, noDeps? По ощущениям, должны быть deps, остальное — хаки, но чувствую, что все очень сложно. Думаю, что в идеале надо строить bem модули, используя интерфейс как ym (или саму ym). Чтобы каждый модуль сказать что ему нужно, а когда оно подключится (если еще не подключено) — запустить с этими объектами. Стоит вообще об этом думать? Может быть еще какие-то мысли появились?
@tadatuta Похоже, я должен это визуализировать ;-)
11.11.2013, 01:15, "Alex Yaroshevich" qfox@ya.ru:
Sergey Belov пишет:
Насколько я представляю, с одной стороны:
Пункт (г) в общем случае (перегрузки всего и вся) это краеугольный камень, мне кажется. Если такая возможность будет без черной магии — мы получим очень мощную платформу для разработки фреймворков.
Почему-то мне кажется, что если будет свобода действий в разработке плагинов — работа над бэмтулзами в целом станет проще и приятнее. Достаточно будет описать как писать команды/служебные библиотеки, как его использовать в дальнейшнем, и т.д. — и практически любой сможет писать ЛЮБОЙ требуемый функционал в виде npm модулей, без ожидания когда вольют его PR и т.п. В общем, я проникся этими плагинами, и полностью за. Практически все можно вынести, оставить только клей для этих модулей. Сам клей заменять смысла нет, он просто проклеивает модули, но его интерфейс будет сложно поменять — поэтому хотелось бы универсальный, но простой вариант. CommonJS тоже неплохо, но сам по себе из коробки не дает требуемой функциональность ;-(. Поэтому и думаю.
В общем, итого тезисно. Пока не знаю, насколько это будет быстро работать.
Ну и так далее, тому подобное.
##
А. Ярошевич
Как лучше пробрасывать npm-пакеты между собой. Интерфейс
ym
через общий объект устраивает?Пришел примерно к такому API.
Или BEM.techs.define, BEM.modules.define, BEM.somethingelse, но хочется, чтобы из BEM наружу торчало 2 метода, а все остальное через модули.
Пара моих мыслей насчет модульности из старой переписки:
@SevInf В принципе, ок. Только в этом случае мы заранее усложняем таск (технологию) введением обработки опций, либо прослойку обработки опций переносим в ядро. Pros: унифицированный интерфейс, меньше понятий — проще дока, ? Cons: сложнее поддержка, меньше гибкости, все внутренние таски станут видны наружу.
Про скрытие лишнего (последний пункт) — я может быть слишком наивный, но перегруженное АПИ очень сильно повышает порог вхождения. Можно продумать вариант, когда таски будут декларироваться отдельно, прокидываться отдельно, но просто. Некий хелпер для
@zxqfox, правильно ли понял, что таск в этом случае не становится командой, пока мы явно этого не скажем?
@SevInf, предлагаю, чтобы он был виден из кода при декларации, но не при вызове из терминала типа
bem task
@zxqfox, да, согласен.
Хотелось бы в добавок к модульности в bem-tools.next получить convention over configuration. Типичная структура проекта более-менее устоялось и можно предполагать ее наличие по умолчанию, а именно:
common
,desktop
,touch
,touch-phone
иtouch-pad
. Некоторые уровни опциональны.desktop
- собирается из блоковcommon
иdesktop
touch-phone
- собирается из блоковcommon
,touch
,touch-phone
touch-pad
- собирается из блоковcommon
,touch
,touch-pad
Хотелось бы, чтоб для подобной структуры сборку не надо было конфигурировать. При этом, для подлючение новой библиотеки следующей этой же схеме ограничилось каким-нибудь ключем в конфиге вида
{"libraries": ["lib1", "lib2"]}
- нужные уровни для библиотеки сами бы включились в процесс сборки бандлов.@SevInf, вообще, я пытаюсь сделать так, чтобы настройки по умолчанию тоже можно было вынести в отдельный npm-пакет.
Банально, в config.js (или make v3) описываем список пакетов, которые надо подключить. Туда прописываем пакет с нужным неймингом — и радуемся. Надеюсь, что будет несколько заготовок. Можно даже в одном базовом пакете несколько разных рекоммендуемых схем описать. Если не нравится — убираем пакет и описываем ручками уровни, и все остальное. Как именно — пока тоже вопрос. Порядок, при подходе с ym, не должен играть сильного значения, но есть нюансы.
Сейчас я думаю, что информацию про уровни надо собирать по необходимости, но всю. Т.е., условно, отдельно получаем список сущностей, отдельно строим граф, если он требуется, отдельно читаем файлы технологий, и т.д. результаты запоминаем. Чтобы можно было делать примерно так: var граф = взятьУровни().взятьБлоки().filter(выкидываем лишние).reduce(но помним про всех и запускаем таски на нодах) граф.filter(...).делаемМагию()
/cc @diunko @scf2k
@SevInf Т.е. для текущей устоявшейся конфигурации будет где-то (хоть в модуле) написано так. Это ок?
Уровень, кстати говоря, смешивается с понятием уровня переопределения и мешает вменяемому восприятию действительного. И не надо забывать, что явное лучше неявного ;-(.
Хотелось бы чтоб для project-stub конфиг условно говоря выглядел как-то так:
И автоматически предпологалась структура проекта и библиотек описанная выше. При этом возможность сконфигурировать проект по своему все равно остается, возможно в каком-то виде, похожем на текущий.
Это в моем понимании не замена явного поведения неявным, а добавление поведения по умолчанию, при этом использующее уже де-факто принятую схему раскладки файлов в проекте.
Имхо, хороший инструмент не должен требовать тонкой настройки чтобы быть хотя бы минимально полезным. Это не отменяет возможность расширения и кастомизации для опытных пользователей, но снижает порог входа для новичков.
Я тут ни какой новой терминологии не изобретал, понятия "уровень блоков" и "уровень бандлов" есть и сейчас. По факту это и есть простые уровни переопределения.
Я бы в 2.0 назвал технологии как-то по-другому.
+1
@SevInf :cactus: Я про в целом — уровень первого типа, уровень второго типа, уровень библиотеки (наверное, тоже есть?), уровень переопределения и т.д. Все смешалось. Уровни переопределения — это одно, уровни блоков и бандлов — это совсем другое. Уровни переопределения содержат уровни блоков и бандлов. Их бы тоже переосмыслить.
@SevInf @scf2k таск? технология сейчас объединяет 2 понятия: набор методов для разработчика, и файлы в блоках и бандлах — для пользователя. второе я предварительно назвал реализацией, но тоже не до конца точно. если первое таск — как реализацию назвать?
Уровни переопределения - это уровни переопределения. Уровни блоков и банлов - это все те же уровни переопределения. Просто в зависимости от того что в них лежит (не в бэм терминах, а функциональных) - мы можем обозвать их как-то по-другому. Но они по-прежнему являются уровнями переопределения.
Под технологией в данном контексте я понимаю то что пишется в "модуле технологии".
@scf2k А модуль технологии — это .bem/techs/tech? или block/tech? Так или иначе, терминология путает. btw, я думаю, что нет смысла отдавать в технологии интерфейс к уровню. В основном технологии нужны исключительно её файлы. Каким-то больше, каким-то меньше, но только реализации в конкретных блоках. Так можно упростить интерфейс, с которым работает технология: Передавать туда список бэм сущностей (узлов) для проекта (или каждый отдельно), и на выходе иметь результат — бэм-сущность (список результатов для узлов), или 1 результат, или 2 списка (из одной реализации получаем две другие промежуточные, например), etc.
Мои general мысли на тему "каким мог бы быть 2.0".
Идея реализации ядра. В качестве предложения на обсуждение, я еще не знаю на сколько она хороша и т.д. Пока просто мысль вслух. Есть стек выполненных "задач", в который по завершении задачи кладется ее id. У каждой задачи есть список id, от которых она зависит и не может выполняться до выполнения их всех. Когда в стеке появляется все из списка, задача может выполниться. Звучит похожим на apw, но отличие в отсутствии связей в чистом виде. Что упрощает расставление зависимостей и должно быстрее работать. В apw перелинковка нод плана после каждого изменения arch отжирает немло времени, что становится заметно на крупных проектах с большим количеством нод.
Пока писал предыдущий абзац, появилась альтернативная мысль. Не смотрел подробно в enb, возможно там сделано так. В стек складывать id задачи и промис на результат ее выполнения. Тогда заивсимые задачи получают возможность сделать часть своей работы до выполнения всех зависимостей, когда выполнилась только часть.
@scf2k ура!
Первые 1, 3, 4 пункты согласен полностью. Пункт 2 — сложности с терминологией, но в целом тоже согласен. Нужно понять что нужно и назвать соотв. образом. Последний пункт — прямая передача не нужна и будет только вредить. Но отбирать возможность запрашивать данные через общее апи, или ядро/некий модуль — плохо.
Ядро, я думаю, стоит разделять на несколько модулей. Смысла отдельном сборщике в целом я не вижу, но какой-то опциональный модуль более тонко управлящий сборкой может быть полезен. С ID, если они будут выглядеть как
bundle/tech
, гдеbundle
(или, лучше,block
) это контекст, а запрашиваться она будет черезtech
— тоже абсолютно согласен. Тут нужны промисы, они сильно упрощают логику в целом.Учитывая последний абзац — промисы как-то так, как описано тут? https://github.com/bem/bem-talk/issues/5 Вроде бы, в таком виде они могут существовать и код будет выглядеть очень просто, куча пространства для оптимизации, т.к. все асинхронное и декларативное.
Круто!
Дааа, на словах мы Лев Толстой!