bem-site / bem-forum-content-ru

Content BEM forum for Russian speak users
MIT License
56 stars 6 forks source link

Альтернативная сборка статики (технологий css, js) для страниц - нужен совет #630

Open shkarupa-alex opened 8 years ago

shkarupa-alex commented 8 years ago

Хочется сделать такой шаблон BEM-сборки, который бы легко интегрировался в код сайта (с точки зрения программиста) и был оптимизирован в плане подключенных CSS/JS файлов. Речь про CMS 1С-Битрикс у которой своя система сборки/объединения статики. Вариант с merged-бандлами не рассматриваем. Для сборки используем enb + bh.

По факту нужно следующее: а) для каждой БЭМ-сущности понять перечень необходимых для ее работы статических ресурсов (включая зависимости) б) этот самый перечень включить в виде HTML-комментария в результирующей HTML непосредственно перед БЭМ-сущностью (чтобы программист знал какие файлы нужно подключить для каждого кусочка HTML)

Пример для bemjson:

{
    block : 'bl-1',
    content : [
        {
            elem : 'elem-1',
            mix : { block : 'bl-2' },
            content : [ ... ]
        }
    ]
}

получить html:

<!--
../../desktop.blocks/bl-1/bl-1.css 
../../desktop.blocks/bl-1/bl-1.js
-->
<div class="bl-1">
        <!--
        ../../common.blocks/jquery/jquery.js 
        ../../desktop.blocks/bl-1/__el-1/bl-1__el-1.js 
        ../../desktop.blocks/bl-2/bl-2.css 
        -->
    <div class="bl-1__el-1 bl-2">...</div>
</div>

Какой вариант вижу я сам: вклиниться в генерацию HTML (BH.apply), вычислять для каждого блока (с учетом миксов), генерировать комментарий и добавлять его в HTML.

Вопросы которые хочу задать:

  1. Есть ли более светлые идеи как сделать описанную задачу?
  2. Есть ли какая-то enb-технология которую можно взять за основу? Особо интересует вычисление CSS/JS необходимых для произвольного узла bemjson
kompolom commented 8 years ago

@shkarupa-alex Не совсем понял ваш пример. Можете написать что должно в итоге получиться в html?

tadatuta commented 8 years ago

@shkarupa-alex я могу рассказать, как плюс-минус такое получить, но меня не покидает уверенность, что на самом деле вы этого не хотите.

Предлагаю сначала описать задачу максимально верхнеуровнево, а я попробую посоветовать реализацию, которая доставит минимальное количество боли.

shkarupa-alex commented 8 years ago

Входные данные (специфика 1С-Битрикс):

  1. Любая страница состоит из шапки, подвала, контента.
  2. Вся функциональность реализуется т.н. компонентами (PHP-код реализующий логику, PHP+HTML-шаблон, реализующий вывод)
  3. Каждый шаблон должен подключать ровно те CSS/JS которые он сам использует. Это нужно для того, чтобы перемещение компонента с одной страницы на другую не требовало переделки.
  4. В каждом шаблоне компонента можно подключать сколько угодно разрозненных CSS/JS. Если это делать правильно (в использованием API), то при рендеринге страницы все CSS/JS которые были подкючены в шапке/подвал (компонентах которые были в шапке подвале) попадут в сборку "template.css / template.js". А те, что были подключены в теле страницы - в сборку "page-XXX.css / page-XXX.js"

В итоге получается что CSS/JS шаблона сайта кешируются и для каждой страницы не скачиваются. А скачивается только то, что на данном типе страниц (список товаров/детальная товара/главная) действительно нужно.

Чтобы из БЭМ-верстки можно было быстро делать шаблоны компонентов, для каждого произвольного DOM-поддерева из сгенерированного сборщиком HTML должно быть максимально очевидно от каких CSS/JS это DOM-поддерево зависит. Наиболее простое решение - в HTML (PHP) комментарии перечислить эти самые CSS/JS. Создавая шаблон компонента из некоторого кусочка HTML программист будет видеть какие CSS/JS ему нужно подключить. Именно это решение я показал в примере https://www.evernote.com/l/AS-PO0Ns7OtKI7oZ-ivE9gzfAjwZHVI5sBc

Таким образом когда производится доработка верстки и генерируются новые HTML становится легко понять что и где нужно изменить (через WinMerge например).

Использовать merged-bundles не хочется по одной причине: в 1С-Битрикс по факту отсутствует понятие "тип страницы". Любая страница может состоять из множества компонентов и добавление/удаление любого из них не должно ломать сайт. Ну и конечно же не все верстальщики настолько продвинуты чтобы быстро и правильно делать конфиги для сборки merged-бандлов.

tadatuta commented 8 years ago

Более-менее понятно, но есть еще ряд вопросов:

1) Если ли причина не генерировать сразу конкретный код подключения стилей и скриптов вместо комментариев, по которым придется подключать вручную?

2) Что считать сущностью, требующей списка зависимостей? Приведу пример, чтобы было понятно о чем вопрос.

{
    block: 'nav',
    content: [
        {
            elem: 'item',
            content: {
                block: 'link',
                url: '#url',
                content: {
                    block: 'icon',
                    mods: { type: 'info' }
                }
            }
        }
    ]
}

Это все один блок nav или 3 разных блока, элемент и модификатор, каждый со своими отдельными зависимостями?

3) После того, как код попал к программисту и он подключил все необходимые зависимости, как дальше развивается проект, если нужно, скажем, добавить модификатор в один из блоков, а у модификатора есть свои собственные зависимости или, наоборот удалить какой-нибудь элемент (и в этот момент определить, нужно ли удалять зависимости элемента или они нужны блоку-родителю)?

shkarupa-alex commented 8 years ago
  1. Такой причины нет, я для упрощения не стал об этом писать. По факту можно генерировать сразу код подключения. Есть тонкости связанные с архитектурой битрикса и иногда этот код нужно будет выносить/копировать в соседний файлик, но по большому счету это будет уже победа если код подключения появится в HTML в виде
  2. Какая сущность требует зависимостей (CSS/JS и в т.ч. по deps.js) это как раз и есть 1 и моих вопросов (в смысле как понять перечень зависимостей). Если же речь о том для каких узлов из приведенного примера нужны вот эти самые комментарии с указанием что подключать - только для узлов-блоков: block: 'nav', block: 'link', block: 'icon'. Но каждый из кодов подключения должен содержать как зависимости текущего блока, так и зависимости всех дочерних (рекурсивно) блоков/элементов/модификаторов.
  3. Рассматриваем ситуацию внесения изменений в уже существующую верстку и необходимость ее переноса на работающий сайт. Верстальщик вносит изменения, пересобирает верстку, отдает ее программисту. Действия программиста: а) Скопировать всю папку со сборкой, полученную от верстальщика на сайт (обновляются/добавляются CSS/JS). Этим мы уходим от необходимости делать merge всех каталогов/файлов верстки. б) Сделать merge старых и новых HTML. В итоге могут быть отличия 2-х типов: изменился HTML-код и/или изменились коды подключения. Эти изменения программист должен точечно перенести в шаблоны соответствующих компонентов.
tadatuta commented 8 years ago
  1. Выносить в отдельные файлы достаточно просто, нужно только определить схему, по которой такие файлы должны создаваться
  2. Да, вопрос был про узлы. Дело в том, что у элементов, модификаторов блоков и модификаторов элементов могут быть свои собственные зависимости, а блоки могут быть вложены в другие блоки. Поэтому просто сжимать полученные зависимости мало, необходимо гарантировать, что будут исключены дублированные зависимости. Битрикс это умеет?
  3. Как все-таки в результате выглядит проект? Есть отдельные компоненты со своими зависимостями и шаблонами (и это отлично мапится на структуру БЭМ-проекта), а как дальше эти отдельные шаблоны превращаются в страницу?
shkarupa-alex commented 8 years ago

Нужно только определить схему, по которой такие файлы должны создаваться

Эту схему я понимаю. Затруднение вызывает вопросы: а) Какую технологию можно для этой задачи взять за основу (есть предположение что нужно изменить поведение bh.apply, переопределив технологию bemjson-to-html) б) Каким образом для конкретного блока/элемента/модификатора bemjson (в рамках bh.apply) получить список всех его зависимостей на CSS/JS (включая зависимости через deps.js)

Будут исключены дублированные зависимости. Битрикс это умеет?

Да, умеет. Даже если 1 и тот же CSS/JS подключен несколько раз, в результирующей странице он появится только однажды. Причем в зависимости от места где он был подключен статический файл он попадет либо в объединенную сборку CSS/JS шаблона, либо в сборку страницы.

Как дальше эти отдельные шаблоны превращаются в страницу?

Страница == PHP (в том числе вызов компонентов) +HTML. Вызов компонента и рендеринг его шаблона происходит на каждый хит. Это если не вдаваться в механизмы кеширования (в т.ч. кеширования отрендеринных шаблонов).

Каждый вызванный компонент рендерит свой шаблон и подставляет результирующий HTML в место вызова. Все необходимые CSS/JS которые затребовали компоненты вставляются в head/body уже после рендеринга всей страницы.

tadatuta commented 8 years ago

Если генерировать готовые файлы для Битрикса, то bemjson-to-html вряд ли имеет смысл использовать.

Я бы предложил следующую схему. У каждого БЭМ-блока есть своя папка. Его непосредственные зависимости описаны в его deps.js-файле. Поэтому для получения полного списка зависимостей не хватает лишь BEMJSON данного блока. Самый простой способ хранить такой BEMJSON — это создать каждому блоку маркдаун-файл с документацией, которая в минимальном случае будет состоять из того самого BEMJSON: { block: 'my-block' }. Тогда можно будет автоматически собрать CSS и JS для каждого блока автоматически.

Такой вариант подходит?

shkarupa-alex commented 8 years ago

Хотелось бы более продвинутую технику, которая учитывала: а) Наличие/отсутствие CSS/JS реализаций блока/элемента/модификатора (не генерировала ничего если они отсутствуют) б) Уровни переопределения в) Не требовала верстальщика делать чего-то дополнительного сверх описанного в документации по БЭМ

tadatuta commented 8 years ago

http://ericdye.it/wp-content/uploads/2015/03/Challenge-Accepted-Meme.jpg

tadatuta commented 8 years ago

Я создал в project-stub ветку forum-630, в которой положил скрипт get-blocks.js.

Принцип такой:

  1. При запуске в аргументе командной строки передается путь до BEMJSON-файла. Например, node get-blocks.js desktop.bundles/index/index.bemjson.js.
  2. Скрипт генерирует папку с бандлами на основе [1]. Например, index.examples/*.
  3. На полученные бандлы натравливается enb.make().

Сейчас сборка будет собирать CSS и JS полностью, так что для решения исходной задачи потребуется создать технологии для ENB, которые бы генерировали файлы в нужном для Битрикса формате. Если с этим потребуется помощь — пиши.

Ну и если решение по какой-то причине не подойдет, то можно обсуждать альтернативы.

voischev commented 8 years ago

@tadatuta :fire:

shkarupa-alex commented 8 years ago

@tadatuta, спасибо за попытку, но не то что нужно.

  1. В получившихся микросборках если у блока есть зависимость, то результирующий CSS/JS будут склеены (например jQuery будет приклеен в каждый блок который от него зависит)
  2. Хочется обойтись без каскадного запуска enb-make

Пока идея следующая: сделать технологию, которая будет проходить по всем блокам и для каждого блока/элемента/модификатора генерировать json-файл с перечислением зависимостей (как списка CSS/JS, в том числе из других блоков). Для каждого deps.js - делать то же самое (рекурсивно). А уже на этапе рендеринга HTML проверять наличие этого сгенерированного файла и в случае его наличия - вкраплять в HTML нужный код.

Вопрос встал вот за чем: как внутри технологии (а точнее внутри метода builder) правильно интерпретировать deps.js (учитывая что он имеет необязательные части и может отменять зависимости). Наверняка есть какой-то уже готовый метод. Если подскажете его или место где можно посмотреть решение аналогичной задачи - мне будет намного проще реализовать эту больную фантазию.

tadatuta commented 8 years ago
  1. В получившихся микросборках если у блока есть зависимость, то результирующий CSS/JS будут склеены (например jQuery будет приклеен в каждый блок который от него зависит)

Это происходит потому что я не менял конфиг сборки для сгенерированных бандлов, они собираются по той же схеме, что и страницы. В данном случае, как я и писал выше, необходимо заменить технологии для сборки CSS и JS на такие, которые бы вместо инлайнинга генерировали необходимый Битриксу формат подключения зависимостей (я с ним не знаком, поэтому сам реализовать не берусь).

  1. Хочется обойтись без каскадного запуска enb-make

Если внести необходимые изменения по п. 1, то enb make будет всего лишь рекурсивно собирать зависимости по уровням переопределения и генерировать списки депендов. Т.е. никакой причины пытаться заменить его на что-то самописное нет.

как внутри технологии (а точнее внутри метода builder) правильно интерпретировать deps.js

Вот технология, которая собирает deps: https://github.com/enb-bem/enb-bem-techs/blob/master/techs/deps.js