Войти с помощью github

Добрый день! Подскажите как правильно собрать несколько страниц в рамках одного проекта. Структура такая: project -page1 -------scroll1 -------scroll2 -------scroll3 -page2 -page3

Как получить отдельную сборку js для scroll1, scroll2, scroll3 без библиотеки i-bem тк хочу загрузить js код каждого скрола в отдельный компонент при интеграции в Битрикс а библиотеку I-bem вывести один раз, например подгрузить в шапке для всего проекта.

у нас есть несколько разделов сайта. Админка, профиль, публичная часть. Сейчас собирается 3 merged бандла. При этом на публичной части много разных страниц. Хотелось бы иметь что то вроде core.js, core.css куда попадут стили и скрипты общие для всех страниц публичной части, и маленькие js и css для каждой отдельной страницы, где будут уникальные стили-скрипты для нее. Как это сделать?

Привет! Я хотел вкрутить юнит тесты в проекте по инструкции https://ru.bem.info/toolbox/enb/enb-bem-specs/, но получил ошибку

Failed to start mocha: Init timeout Unsafe JavaScript attempt to access frame with URL about:blank from frame with URL

Решил попробовать на базовом проекте (https://github.com/bem/project-stub), но получил такой же результат. Посмотрел какие файлы формируются и заметил, что в конечных файлах тестов пустые html и css файлы. Пропущена какая-то зависимость?

Здравствуйте. Разворачиваю bem-site-engine. https://github.com/bem-archive/bem-site-engine Столкнулся со следующе ошибкой: [2016-11-29 18:33:54] DEBUG app.app.node.js: app initialization [2016-11-29 18:33:54] DEBUG _type.provider_type_file.node.js: make directory backups/0 [2016-11-29 18:33:54] DEBUG _type.provider_type_file.node.js: copy file from backups/data.json to backups/0/data.json [2016-11-29 18:33:54] ERROR model.model.node.js: Error occur while loading model ENOENT: no such file or directory, stat 'backups/data.json' [2016-11-29 18:33:54] DEBUG app.app.node.js: starting server [2016-11-29 18:33:54] ERROR app.app.node.js: TypeError: Cannot read property 'redirects' of undefined

Верно ли я понимаю, что надо сделать snapshot? Если да, как его сделать? Спасибо.

Проект на базе project-stub. Используются:

  1. bem-core v 3.0.1
  2. bem-components v 3.0.1
  3. enb

Около 100 страниц накопилось. Сборка идет около 30..70 с (30 000..70 000 мс) Можно ли что-то подкрутить для увеличения скорости?

Только начинаем внедрять, есть вопрос, почему зависимости из BEMJSON создаются автоматически, а в шаблоне -- нет. Есть какая-то идеологическая причина? Или это ограничение сборщика enb текущей версии?

Появилась необходимость собирать не только основной файл js но и подключать к нему web worker. Как Реализовать такой функционал в пределах БЭМ проекта?

Вопрос про физическое наименование/расположение папок и файлов для подсовывания enb.

Для модикатора использую _modName/blockName_modName.*, для элемента __elemName/blockName__elemName.*.

А для элемента блока с определённым модификатором. Вопреки ожиданиям, _modName__elemName/... не работает. Хотя для _modName1_modName2, напр., -- запросто.

Есть к.-то паттерн подходящий?

По запросу в поисковик "i-bem__dom_init_auto" я нашел кучу незавершенных тем. Решился написать на форум, увидев, что подобным интересуюсь не только я. Думаю, понятно о чем пойдет речь. Стоит сразу 2 задачи: вынести ym, jquery, i-bem и т.д в отдельный файл, и заводить не по domReady. Хотелось бы решить максимально не велосипедя.

Прямо в документации сказано: noDeps (массив/объект) — можно отменить какую-то зависимость (например, i-bem__dom_init_auto).

Хотя, как я понимаю, принято категорически избегать noDeps. Видимо, по тем же причинам что и !important в css. Так или иначе, не могу его исплючить из финального deps, он все равно приезжает. Ну и если кто-то найдет этот пост, дабы уж не разметать все по кускам, напишу тут, что, по-идеи, достаточно собрать бандл с ym и блоком 'page'. А уж потом можно вторым файлом бандл со своими блоками лепить. Но! Тут то и встает у меня основная проблема.

Представим,что у нас такая картина:

//ym, i-bem и вот это все.
<script src="/assets/bootstrap/bootstrap.js" type="text/javascript"></script>
//В этом бандле один единственный блок
<script src="/bundles/index/index.js" type="text/javascript"></script>

Не работает. И нет ошибки в консоли. i-bem__dom_init_auto находится в конце файла bootstrap.js - не работает. Подрубаю к моему к моему index.js в сборку i-bem. Теперь мой блок находится в одном файле с i-bem__dom_init_auto, и все еще ниже него. Результат: теперь работает. Я бы и не против замешивать "стартер" с ручным вызовом в каждый свой бандл, кода то там совсем чуть-чуть. Но как тогда исключить его из сборки bootstrap.js?

Такая же проблема будет если просто взять https://yastatic.net/bem-components/latest/touch-pad/bem-components.js.Но там мои блоки хотя бы через раз работают. Да, именно так. Просто сижу и тыкаю ctrl + r, иногда код не отрабатывает. (Могу даже дать ссылку боевого сайта, где такая проблема) Успел твой файл скачаться до инициации? Ну и ладненько, радуйся.

Казалось бы, логичный кейс. Зачем мне заворачивать все в один бандл, если страниц на сайте много? Я ведь не ландинг делаю, пущай в кэш браузера запомнит основу. Давайте наконец-то разберемся.

Как то давно, мной был задан вопрос https://ru.bem.info/forum/793/ по реализации разделения css стилей и последующего их инлайна на html страницу.

Подход довольно простой.

  1. Собираем два разных бандла, первый critical, второй со всеми стилями.
  2. Превращаем файл critical.css в js файл, через инлайн файла module.exports = '....'
  3. Подключаем этот файл обычным require в виде элемента блока page {elem: 'css', content: require('desktop.bundles/critical/critical.css.js')}

В critical бандле подключается только один единственный блок critical (простите за каламбур) у которого в зависимостях описаны все блоки которые нужно заинлайнить.

Выложил выжимку своего конфига на enb https://gist.github.com/JiLiZART/efa6b23c478b17c4708b931a44fce996

Я использую bemtree, но для bemjson будет даже проще.

Есть у этого способа и недостатки, стили, которые инлайнятся в страницу, дублируются в бандле со всеми остальными стилями. Для решения этой проблемы я навоял вычитание deps'ов друг из друга в этом PR https://github.com/enb/enb-bem-techs/pull/190 Что поможет в дальнейшем вычитать все блоки critical бандла из основного

Привет! Хочу рассказать о полезной штуке, которую мы написали в Яндекс.Директе.

direct-dev-server - это веб-сервер для заданной ENB-ноды с автоматической пересборкой бандлов при изменении исходных файлов. Сервер имеет кэш и собирает бандлы только если исходные файлы изменились (в отличие от enb-server, который собирает при каждом http-запросе).

Его удобно использовать тогда, когда нужно часто менять код и пересобирать бандлы (например, во время отладки кода блоков). За счет того, что сборка запускается сразу же при изменении файлов и за счет использования кэша готовый для отладки набор бандлов формируется намного быстрее, чем, например, при использовании ENB в режиме сервера.

Как использовать

  1. Устанавливаем
npm i direct-dev-server
  1. Запускаем
node node_modules/direct-dev-server -b <название_бандла>
  1. В консоль выводится ссылка, открываем ее в браузере

    Конфигурационный файл

Конфигурационный файл должен лежать в корневой директории и называться .dev-server.js.

Пример:

module.exports = {
    bundles: 'bundles',             // папка с бандлами
    levels: [                       // список уровней переопределения
      'common.blocks'               // (в них будут отслеживаться изменения файлов)  
      'desktop.blocks'
    ],     
    defaultTarget: '?.test.html',   // таргет начальной страницы (будет открыта в браузере при старте)
    targets: {                      // зависимости таргетов от БЭМ-технологий
        '?.js': ['js'],
        '?.test.js': ['test.js'],
        '?.css': ['css']
    }
};

Пытаюсь настроить enb на простую сборку js и css, без bemhtml. Возможно ли получать bemdecl на лету, на основе html, при помощи этого:

https://github.com/bem-contrib/html2bemjson

Попытался написать даже свою технологию для enb, но как я понимаю, она смотрит только на уровни переопределения, когда уже есть готовый bemdecl.

Вроде, даже json адекватный выходит, если ручками прогнать. Но как сагрить на все это сборщик?

Проблема довольно банальна - ссылка на картинку блока из CSS файла блока не работает. Единственный работающий вариант это:

...
background-image: url(../../common.blocks/header/images/bg-header.png)
...

Фактически это абсолютный путь к блоку, в который так-же входит и путь к папке блоков common.blocks, что на мой взгляд совершенно неверно. Т.е. если я допустим захочу вынести потом этот компонент в допустим папку blog.blocks то получается надо будет бегать и пути менять. Или переименую я блок - та-же история.

Вот такой вариант:

...
background-image: url(images/bg-header.png)
...

работать отказывается

Borschik (через enb - project-stub) чё-то как-то не помог - такой путь он просто проигнорировал. Пытался крутить конфиг .borschik но без особого успеха (но тут я сильно глубоко не рыл).

Итого вопрос - как всё-таки идеологически верно указывать пути к картинкам блока в CSS-файлах блока?

Нужно получать на выходе файл с шаблонами бандла без обёрточного кода BEM-XJST (BEM-XJST User-code Start ... BEM-XJST User-code End).

Пока придумал добавить свою технологию, которая из имеющегося .bemhtml.js создавала к.-ндь .bemhtml.raw.js, выкусывая всё, кроме шаблонов.

Есть ли более изящный способ?

В опциях к самому techs/bemhtml ничего годного не вижу.

...
11:49:48.427 - [rebuild] [desktop.bundles\merged\merged.dirs] files
11:49:53.753 - [failed] [desktop.bundles\merged\merged.css] stylus
11:49:53.759 - [failed] [desktop.bundles\merged\_merged.css] borschik
11:49:53.759 - build failed
Error: D:\_my-work-tasks\project\desktop.bundles\merged\merged.css:21:14
   17| /* ../../template.blocks/header/header.styl:begin */
   18| @import "../../template.blocks/header/header.styl";
   19| /* ../../template.blocks/header/header.styl:end */
   20|
   21| /* ../../desktop.blocks/ico-location/ico-location.styl:begin */
--------------------^
   22| @import "../../desktop.blocks/ico-location/ico-location.styl";
   23| /* ../../desktop.blocks/ico-location/ico-location.styl:end */
   24|

Failed to @extend ".link"

    at D:\_my-work-tasks\project\node_modules\enb-stylus\node_modules\stylus\lib\visitor\normalizer.js:406:17
    at Array.forEach (native)
    at Normalizer.extend (D:\_my-work-tasks\project\node_modules\enb-stylus\node_modules\stylus\lib\visitor\normalizer.js:402:17)
    at Normalizer.visitGroup (D:\_my-work-tasks\project\node_modules\enb-stylus\node_modules\stylus\lib\visitor\normalizer.js:279:8)
    at Normalizer.Visitor.visit (D:\_my-work-tasks\project\node_modules\enb-stylus\node_modules\stylus\lib\visitor\index.js:28:40)
    at Normalizer.visitBlock (D:\_my-work-tasks\project\node_modules\enb-stylus\node_modules\stylus\lib\visitor\normalizer.js:232:27)
    at Normalizer.Visitor.visit (D:\_my-work-tasks\project\node_modules\enb-stylus\node_modules\stylus\lib\visitor\index.js:28:40)
    at Normalizer.extend (D:\_my-work-tasks\project\node_modules\enb-stylus\node_modules\stylus\lib\visitor\normalizer.js:423:22)
    at Normalizer.visitGroup (D:\_my-work-tasks\project\node_modules\enb-stylus\node_modules\stylus\lib\visitor\normalizer.js:279:8)
    at Normalizer.Visitor.visit (D:\_my-work-tasks\project\node_modules\enb-stylus\node_modules\stylus\lib\visitor\index.js:28:40)

Похоже, что какой-то блок зависит от link (используется @extend ".link"), но в сборку link попадает позже

Вопросы:

  1. как (где) можно посмотреть файлы с @import?
  2. правильно ли я понял суть ошибки?

И ещё, понимаю, что торможу, но есть какой-то способ сохранять комментарии разработчика в итоговом файле css?

Ребята, если вы чувствуете в себе силы помочь нам и дописать технологию enb-css, чтобы она научилась поддерживать произвольные плагины postCSS — приходите в https://github.com/enb/enb-css/issues/9!

Что есть сейчас: отличная технология для сборки стилей с покрытием тестами и хорошей документацией. Она уже сейчас умеет postCSS для автопрефиксера, но по нелепой случайности не позволяет добавлять другие плагины. В результате приходится дополнительно подключать технологию про postCSS и заново парсить стили. Помогите сделать хорошо!

@blond, сможешь описать API в issue?

Возникла задача перенести часть компонент из "генерящихся на лету" в статику (в частности, чтобы наладить совместную разработку с коллегами, не использующими систему сброки).

Напр., в соответствии с описанным в посте про dist-поставки, отдельно подключать для bem-components components.dev.js+bemhtml.js и components.dev.css или минимизированные аналоги.

Насколько понимаю, просто отключать уровни в make.js не годится, надо как-то более поэлегантней подходить?

Использую enb и локальный сервер для разработки. При помощи enb make из gulp генерятся "боевые" шаблоны для Phalcon/php сервера.

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

Вот что выдает консоль: ссылка Вот репозиторий: ссылка

Добрый день! Внимательно прочитал всю доступную документацию в старом виде и в новом, несколько статей, посмотрел несколько вебинаров и лекций. Но некоторые моменты всё равно ускользнули от моего внимания и понимания. В целом эта непонятная ситуация причиняет мне физический дискомфорт. Боюсь, что для понимания многих вещей, придется просмотреть много кода, что бы найти примеры использования, а это камень в огород документации. Без ответа на эти вопросы, я буду плавать в методологии и не смогу ей воспользоваться.

Из документации я не понял:

1. Шаблонизация в браузере когда и зачем нужна? Я предполагаю, что весь HTML будет собираться на сервере, в том числе, что динамично будет отправляться клиенту. Но, коль есть возможность компилировать в браузере, хотелось бы узнать о плюсах и кейсах, когда это может понадобиться. Что, касательно ресурсов, насколько это ресурсозатратно?

2. Возможность частичной сборки и компиляции со статичными html файлами Многие элементы интерфейса - статичные, например, шапка, меню, футер, общие лейауты. Собирать их отдельно для каждого клиента - бессмысленно. Возможно ли как-то объединять уже собранный, статичный HTML и динамичные блоки?

3. Документация про сборку Я прочитал весь раздел про enb, но там скорее кейсы, чем сама архитектура. Мне непонятно, как организовать сборку для проекта в целом.

4. Как организовать сборку для дева, прода, лайв В продолжение предыдущего вопроса - для разработки и для прода требуются разные настройки. Я правильно понимаю, что разные настройки обеспечиваются разными файлами по типу make.js ?

5. Документация про декларацию Я не нашел цельной информации про декларацию (?.bemdecl.js), и всё, что я про это знаю - частички из статей про enb, из-за этого складывается ощущение, что я чего-то не догоняю.

_6. Почему и зачем есть BEMHTML и bh, какой для каких ситуаций лучше _ Я долго пытался понять - что делает bh, пока не понял, что это - еще один шаблонизатор, такой же, как BEMHTML. Так в чём же разница, и как так получилось, что есть два шаблонизатора? Какой из них под какие цели заточен? И, кстати, про bh нет документации.

_7. Где доки про BEMTREE, когда что лучше использовать _ Про BEMTREE лишь сказано, что синтаксис "Такой же, как в BEMHTML, но только с двумя режимами", при всём при том, что это - важный и основной инструмент при сборке. Очень хотелось бы увидеть примеры и объяснения, как делать шаблоны для BEMTREE.

8. Доки про SASS|LESS| любые модули Основной инструмент библиотеки для css - stylus, по историческим причинам. Хотелось бы узнать, как можно использовать другие препроцессоры. Я часто встречал мнение, что БЭМ - навязывает свой стек. Я понимаю, что это не так, просто инструменты дефолтные такие. Хотелось бы узнать, как можно в сборку включать те, что соответствуют моему стеку.

9. Контроллеры для сборки, практики BEM - штука хорошая, но кажется очень замкнутой в себе из-за того, что до конца не ясен сам процесс сборки и связь с внешним миром. Во всех статьях и гайдах говорится в-основном о статичных сайтах. И из-за этого, совсем мне не понятно, как сделать динамичный сайт, как организовать динамичную и частичную сборку, роутинг и т. д.

10. Шапка, лейаут в общем html Возможно, мой мозг еще не переключился в БЭМ-область, но мне до конца не ясно, как сделать общие части интерфейса для всех страниц сайта - каждый раз подключать header, content, footer?

11. Подключение скриптов, стилей, других библиотек. Если подключение своих скриптов, всё худо-бедно понять можно, то как подключить скрипты библиотек? Их ведь нужно указать в head (а некоторые скрипты в футере). Как же это всё делается в рамках шаблонов, страниц? Хардкодить?

12. Какие практики бандлов Из документации мне совсем не понятно что такое и для чего нужны бандлы. Как я понял - это собранные пакеты css и js, но куда их нужно пихать и зачем - непонятно.

13. Борщик Для чего борщик существует внутри enb, ведь в enb есть другие инструменты, для работы с файлами. В чем его отличие и назначение?

Возможно, многие вопросы очевидные или неправильно сформулированы, про неправильное пользование той или иной технологией. Каждый из этих вопросов - для меня важный, прошу, если вы знаете ответ или имеете мнение хоть по одному из них - не стесняйтесь.

Накидал docker контейнер для запуска project-stub - https://github.com/nejtr0n/bem Возможно кому то пригодится. Запускается просто:

git clone https://github.com/nejtr0n/bem.git && cd bem
docker-compose up

При первом запуске project-stub соберётся в папку bem.

Добре!

Есть пример как запустить тесты под BH engine

https://github.com/enb/enb-bem-specs/blob/master/examples/silly/.enb/make.js

Но как выяснилось это не работает.

Смотрите. Мне важно, чтобы блок был добавлен в html до исполнения JS.

зовут его b-legend

Для того, чтобы он попал в тесты используется специальный слой переопределения

app-specs.blocks где и лежит спец файл BH

app-specs.blocks/b-legend/b-legend.bh.js

Внутренность у него проста:

module.exports = function(bh) {
    bh.match('spec-content', function () {
        return {block: 'b-legend'};
    });
};

И да используется библиотека bem-pr где существует блок spec-content, переопределяя который по идее внутри должны получить блок b-legend.

Все бы хорошо, но не работает сборка bemdecl файлов в enb-bem-specs.

Добавил слои:

layers = [
   'app.blocks',
   'app-specs.blocks'
];

specs.configure({
    langs: false,
    destPath: 'specs',
    levels: layers,
    templateEngine: {
        templateTech: require('enb-bh/techs/bh-bundle'),
        templateOptions: {
            devMode: false
        },
        htmlTech: require('enb-bh/techs/bemjson-to-html'),
        htmlTechOptionNames: { bemjsonFile: 'bemjsonFile', templateFile: 'bhFile' }
    },
    sourceLevels: [
        { path: 'libs/bem-pr/spec.blocks', check: false }
    ].concat(layers),

    jsSuffixes: ['js'],
    specSuffixes: ['spec.js']
});

Запустил таск, появилась куча файлов в spec/b-legend:

И даже b-legend.base.bemdecl.js, содержит нужный блок. Но после всех mergeDeps, mergeDecl этот блок не попал в сборку BH. Но попал в сборку JS.

Оказывается вся загвоздка в том, что при сборке HTML, не учитывается базовая зависимость ?.base.bemdecl.js и следовательно ?.bemdecl.js

Что может спасти ситуацию?

Добавить эти зависимости для сборки html используя mergeDeps:

// Client BEMHTML
        nodeConfig.addTechs([
            [depsByTechToBemdecl, {
                target: '?.js.template.bemdecl.js',
                sourceTech: 'js',
                destTech: 'bemhtml'
            }],
            [depsByTechToBemdecl, {
                target: '?.spec-js.template.bemdecl.js',
                sourceTech: 'spec.js',
                destTech: 'bemhtml'
            }],
            [mergeBemdecl, {
                target: '?.template.bemdecl.js',
                sources: [
                    '?.js.template.bemdecl.js',
                    '?.spec-js.template.bemdecl.js',
                    '?.bemjson.bemdecl.js'
                ]
            }],
            [depsTech, {
                target: '?-pre.template.deps.js',
                bemdeclFile: '?.template.bemdecl.js'
            }],
            [mergeDeps, {
                target: '?.template.deps.js',
                sources: ['?.bemdecl.js', '?-pre.template.deps.js']
            }],
            [files, {
                depsFile: '?.template.deps.js',
                filesTarget: '?.template.files',
                dirsTarget: '?.template.dirs'
            }],
            [templateEngine.templateTech, templateEngineOpts]
        ]);

Доброго всем времени суток. Долго думал о внедрении БЭМ в проекты... И сейчас назревает новый. Он ещё не утверждён, но я уже обдумываю его реализацию. Планируется следующая схема:

БЭМ (frontend) <-- REST Api --> Express (backend).

Планируется сделать "одностраничное приложение". Но как всегда у меня происходит, в голове всё выглядит как в сказке, но на практике ловлю стопор.

Для вёрстки планирую использовать project stub. Но как правильно подойти к этому моменту?

Опишу вообще как я вижу процесс в абстракции: В проекте лежит каталог bem(project-stub).

Там я верстаю страницы и показываю их заказчику, он радуется. Далее я собранные bemtree + bemhtml подключаю в продакшине. И работаю уже непосредственно с разработанным REST Api + bemtree + bemhtml. В общем стоит задача минифицировать время между вёрсткой демо страниц и продакшин.

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

Буду благодарен за ответы :)

Как это можно сделать?

Подскажите, есть где-то хорошее руководство по созданию технологий для enb?

Всем привет.

Я один из немногих, кажется, кто сейчас использует возможность посылать запросы из bemtree. Одна из причин, по которой я так делаю - полная независимость блоков, то есть блок сам знает, какие данные ему нужны. Однако асинхронный bemtree мне неудобен. Я какое-то время назад собирался написать об этом bem-team, с предложением создать синхронный аналог, но оказалось, что работа над таким аналогом уже идёт и, в принципе, на него уже можно переходить. Останавливает меня от перехода только всё то же желание хранить информацию о том, как получать данные для блока, в папке блока.

Эта была проблема. Теперь о том, каким я вижу решение. Мне кажется, можно хранить информацию о получении данных в файлах отдельной технологии, скажем, block.data.js. Тут всё просто и понятно. Сложность в том, что хотелось бы, чтобы при сборке к каждому такому блоку прибавлялась информация о содержимом файлов этой технологии тех блоков, от которых он зависит - для того, чтобы было легко сформировать один запрос за всеми данными, нужными для отрисовки блока.

Зачем я пишу здесь:

  1. Чтобы получить советы по реализации такой технологии. У меня есть опыт написания технологий для enb, но обычно они проще.
  2. Чтобы услышать мнения о подходе в целом. Есть ли какие-то проблемы, которые я не вижу?

Может кому-нибудь и пригодится. За пару месяцев работы с БЭМом я подметил для себя 3 вида сборки бандлов:

  • когда изменяется непосредственно bemjson
  • когда изменяется bemhtml блока
  • когда изменяются скрипты и стили

Причем только первые два вида могут влиять на конечную структуру html и скрипты и стили. Третий вид изменяет только подключаемые скрипты и стили. Общее здесь - скрипты и стили. Они могут быть модифицированы в любом из вариантов. Из этого следует, что будет как-то нерационально генерить каждый раз html при изменении скриптов или стилей.

А ведь они, в принципе, правятся довольно частенько.

Следовательно нужна такая сборка, которая не делала бы лишних дейтсвий: например, разработчик изменил css, а enb взял бы и пересобрал только css. Еще лучше, если бы эта работа была сопряжена с галповским вотчем.

Сейчас у нас на работе есть подобная сборка, но она не такая гибкая, как хотелось бы. К тому же начальник на днях надоумил меня написать свою. Изначально мне эта идея показалась бредом (зачем писать, когда уже есть и работает), но потом посидев вечер и ночь перед компьютером, у меня стало получаться что-то работоспособное. Потом я стал немного допиливать, допиливать и вот допилил, думаю я. Дим, если читаешь эти строки, знай - я тебе реально благодарен)) Честно!

Так вот, работает эта сборка в 4 режимах в связке с вотчем и устроена слегка костыльно. Сначала о режимах:

full - пересобирает абсолютно все nofull - пересобирает измененные бандлы и все скрипты и стили nofull_css - "по умолчанию" пересобирает только стили nofull_js - "по умолчанию" пересобирает только скрипты

Сама костыльность заключается вот в чем. Для того чтобы узнать изменился бандл или нет, в папке с ним создается файл формата .uptime_[0-9]+ в названии которого находится дата последней модификации bemjson файла. Далее при обходе бандла скрипт смотрит на время модификации bemjson и на этот чудо файл и путем просто сравнения решает, изменялся ли bemjson файл или нет. Ну и далее все ясно: генерить новый html или идти дальше. "По умолчанию" я выделил в кавычки вот почему, эти режимы могут пересобирать измененные бандлы, но генерить они будут помимо html, или css или js. Поэтому их лучше и должно использовать при изменении css или js. Пожалуй, на этом все.

PS. Самое главное) После этой небольшой проделанной работы, хотелось бы выразить огромную благодарность всем участникам форума, которые отвечали на мои бестолковые вопросы ( отдельная благодарность Владимиру Гриненко за его ангельское терпение и постоянный труд по развитию и донесению идеологии БЭМа массам)), а также моему начальнику Диме, который несмотря на свою загруженность, помогал и помогает мне в освоении БЭМа, (и не только БЭМа), и без которого вряд ли бы эта сборка была написана. Спасибо вам, ребята, огромное!

Сначала gulpfile, как этим всем пользоваться

var gulp = require('gulp');
var watch = require('gulp-watch');
var enb = require('enb');
gulp.task('watch', function (cb) {
    watch('desktop.bundles/**/*.bemjson.js', function () {
        enb.make( [], { mode: 'nofull' } );
    });
    watch( '*.blocks/**/*.js', function () {
        enb.make( [], { mode: 'nofull_js' } );
    });
    watch( '*.blocks/**/*.css', function () {
        enb.make( [], { mode: 'nofull_css' } );
    });
    watch( '*.blocks/**/*.bemhtml', function () {
        enb.make( [], { mode: 'full' } );
    });
});

Собственно make.js

var path = require('path');
var fs = require('fs');
var platforms = ['desktop'];
var techs = {
    // essential
    fileProvider: require('enb/techs/file-provider'),

    // optimization
    borschik: require('enb-borschik/techs/borschik'),

    // css
    sass: require('enb-sass/techs/css-sass'),

    // js
    browserJs: require('enb-js/techs/browser-js'),

    // bemtree
    // bemtree: require('enb-bemxjst/techs/bemtree'),

    // bemhtml
    bemhtml: require('enb-bemxjst/techs/bemhtml'),
    bemjsonToHtml: require('enb-bemxjst/techs/bemjson-to-html')
},
enbBemTechs = require('enb-bem-techs'),
levels = [
    'common.blocks',
    'jquery.blocks',
    'desktop.blocks'
];

function getUpdateTime( file ) {
    var mtime = 0;
    try {
        mtime = +new Date(fs.statSync( file ).mtime)/1000;
    } catch(e) {
        return 0;
    } finally {
        return mtime;
    }
}

function createUpdadeFile( path, time ) {
    fs.closeSync(fs.openSync( path+'.uptime_'+time, 'w'));
}

function isUpdatingFile( path, time ) {
    var files = fs.readdirSync( path );
    var up_files = [];
    for( var i = 0; i < files.length; i++ ) {
        var file = files[i];
        if( /^\.uptime_[0-9]+$/.test( file ) ) {
            if( file !== '.uptime_'+time ) {
                fs.unlinkSync( path+file );
            } else {
                up_files.push( file );
            }
        }
    }
    if( up_files.length === 0 ) {
        createUpdadeFile( path, time );
        return true;
    }
    return false;

}

module.exports = function(config, sa) {

    // создаем папки merged в сборках бандлов
    platforms.forEach(function (platform) {
        var node = path.join(platform + '.bundles', 'merged');

        if (!fs.existsSync(node)) {
            fs.mkdirSync(node);
        }
    });

    var isFull = true;
    var noFull = 'all';


    config.mode( 'full', function() {
        isFull = true;
    });

    config.mode( 'nofull', function() {
        isFull = false;
    });
    config.mode( 'nofull_js', function() {
        isFull = false;
        noFull = 'js';
    });
    config.mode( 'nofull_css', function() {
        isFull = false;
        noFull = 'css';
    });



    config.nodes('*.bundles/*', function(nodeConfig) {
        var timeUpdateBem = getUpdateTime( path.dirname(nodeConfig.getPath())+'/'+path.basename(nodeConfig.getPath())+'/'+path.basename(nodeConfig.getPath()) + '.bemjson.js' );

        // если нет bemjson файла - выходим отсюда
        if( timeUpdateBem == 0 ) {
            if( path.basename(nodeConfig.getPath()) !== 'merged' ) {
                console.log( 'error: bundle ' + path.basename(nodeConfig.getPath()) + ' no bemjson-file' );
            }
            return;
        }
        if ( !isFull ) {
            isFull = isUpdatingFile( path.dirname(nodeConfig.getPath())+'/'+path.basename(nodeConfig.getPath())+'/', timeUpdateBem );
        }
        if( !isFull ) {
            nodeConfig.addTechs([
                [enbBemTechs.levels, { levels: levels }],
                [techs.fileProvider, { target: '?.bemjson.js' }],
                [enbBemTechs.bemjsonToBemdecl,  { target: '../merged/?.bemdecl.js' }],
                [enbBemTechs.deps, { bemdeclFile: '../merged/?.bemdecl.js', target: '?.deps.js' }],
            ]);
        } else {
            nodeConfig.addTechs([
                // essential
                [enbBemTechs.levels, { levels: levels }],
                [techs.fileProvider, { target: '?.bemjson.js' }],
                [enbBemTechs.bemjsonToBemdecl,  { target: '../merged/?.bemdecl.js' }],

                [enbBemTechs.deps, { bemdeclFile: '../merged/?.bemdecl.js', target: '?.deps.js' }],
                [enbBemTechs.files],

                // bemhtml
                [techs.bemhtml, { sourceSuffixes: ['bemhtml'], forceBaseTemplates: true, target: '../merged/?.bemhtml.js' }],

                // html
                [techs.bemjsonToHtml, { bemhtmlFile: '../merged/?.bemhtml.js', target: '../merged/?.html' } ],
            ]);
            nodeConfig.addTargets([ '../merged/?.html']);
        }
    });

    config.node('desktop.bundles/merged', function(nodeConfig) {
        var dir = path.dirname(nodeConfig.getPath());
        var bundles = fs.readdirSync(dir);
        var bemdeclFiles = [];
        var depsFiles = [];
        var targetsArr = [];
        var techsArr = [
            [techs.sass, {
                target: 'main.css',
                sourcemap: false,
                autoprefixer: {
                    browsers: ['ie >= 10', 'last 2 versions', 'opera 12.1', '> 2%']
                }
            }],
            [techs.borschik, { source: 'main.css', target: 'main.min.css', tech: 'cleancss', minify: true }],
            [techs.browserJs, { includeYM: false, target: 'main.js' }],
            [techs.borschik, { source: 'main.js', target: 'main.min.js', minify: true }],
        ]
        bundles.forEach(function (bundle) {
            if (bundle === 'merged' || bundle === '.bem') return;
            var node = path.join(dir, bundle);
            var target_bemdecl = bundle + '.bemdecl.js';
            var target_deps = bundle + '.deps.js';
            bemdeclFiles.push( target_bemdecl );
            depsFiles.push( target_deps );
            nodeConfig.addTechs([[enbBemTechs.provideDeps, { node: node, source: target_deps, target: target_deps }],]);
        });
        nodeConfig.addTechs([
            [enbBemTechs.mergeDeps,  { sources: depsFiles }],
            [enbBemTechs.files, { depsFile: '?.deps.js' } ],
            [enbBemTechs.levels, { levels: levels }],
        ]);
        if( noFull === 'css' ) {
            nodeConfig.addTechs([
                techsArr[0],
                techsArr[1],
            ]);
            targetsArr.push( 'main.min.css' );;
        } else if( noFull === 'js' ) {
            nodeConfig.addTechs([
                techsArr[2],
                techsArr[3],
            ]);
            targetsArr.push( 'main.min.js' );;
        } else {
            nodeConfig.addTechs([
                techsArr[0],
                techsArr[1],
                techsArr[2],
                techsArr[3],
            ]);
            targetsArr.push( 'main.min.css' );
            targetsArr.push( 'main.min.js' );
        }
        nodeConfig.addTargets(  targetsArr );
    });


};

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

config.nodes('*.bundles/merged', function(nodeConfig) {
        var dir = path.dirname(nodeConfig.getPath()),
        bundles = fs.readdirSync(dir),
        bemdeclFiles = [];
        bundles.forEach(function (bundle) {
            if (bundle === 'merged' || bundle === '.bem') return;
            var node = path.join(dir, bundle),
            target = bundle + '.bemdecl.js';
            bemdeclFiles.push(target);
        });
        nodeConfig.addTechs([
            [enbBemTechs.mergeBemdecl,  { sources: bemdeclFiles }],
        ]);
        nodeConfig.addTarget( 'merged.bemdecl.js' );
    });

И выдает ошибку There is no tech for target desktop.bundles\merged\example.bemdecl.js Что не так? Заранее спасибо

Рассмотрим 3 случая merged-сборки проекта в режиме watch: 1 - изменение бандла (bemjson) 2 - изменение css, js шаблона 3 - изменение самого шаблона (bemhtml)

При изменении бандла все просто, запускается enb-make и далее все происходит автоматически. А вот как быть при 2 остальных случаях? Не хотелось бы пересобирать весь проект при изменении одного блока, который используется в 2 бандлах, к примеру, из 50.

Как вариант: можно проходиться по депсам бандлов, сравнивать с измененным и уже от этого исходить. Но может есть уже какое-то готовое решение? Заранее спасибо.

Не руками же)

Добрый день.

  1. Как можно настроить make.js, чтобы он в бандл: html файлы, css файлы и js файлы складывал в разные папки с группировкой по этим типам?
  2. Не нашел, есть ли возможность штатными средствами прикрутить css препроцессор (sass/less) ?