В статье речь пойдет о сборке БЭМ-проектов с помощью бандлера Webpack. Я покажу один из примеров конфигурации, не нагружая читателей лишними сущностями.  Материал подойдет тем, кто только начинает знакомство с БЭМ. Сначала коснемся теоретических аспектов методологии, а в разделе «Практика» я покажу, как их можно применить. Если вы впервые слышите о БЭМ и хотите познакомиться с ним самостоятельно, держите документацию. БЭМ — методология, которая применяется для организации проектов любого масштаба. Её разработали Яндекс и сперва использовали только в работе своих сервисов, но позже опубликовали в общем доступе.  БЭМ расшифровывается как “Блок, Элемент, Модификатор”.  Блок — сущность с автономной архитектурой, которая может повторно использоваться. Блок может содержать собственные элементы. Элемент — составная часть блока. Элемент может использоваться только внутри родительского блока. Модификатор — сущность, которая изменяет отображение, состояние или поведение блока. Эти компоненты лежат в основе методологии. Они обеспечивают красоту и удобное разделение кода. Более подробно об их устройстве написано в документации. Документация по БЭМ написана обстоятельно. Однако есть одно “но”: высокий порог вхождения в материал. Если с основами верстки можно разобраться, прочитав одну страницу документации, то вопрос сборки проекта обстоит сложнее.  Почему речь зашла о сборке проекта? При работе над масштабным проектом каждый сталкивается с проблемой организации кода. Хранить весь код большого проекта в одном файле неудобно. Разбивать код на несколько файлов, затем собирать его вручную — тоже не лучший выход. Для решения этой проблемы используются сборщики, или бандлеры, которые автоматизируют преобразование исходного кода проекта в код, готовый к отправке в продакшн. Напомню: далее подразумевается, что у читателей есть базовые навыки работы с Webpack. Если прежде вы с ним не работали, рекомендую для начала познакомиться с этим инструментом.  В документации БЭМ даются рекомендации по сборке проектов. В качестве примеров предлагаются только два варианта: сборка при помощи ENB и Gulp. ENB — утилита, разработанная специально для сборки БЭМ-проектов. Она способна работать с сущностями БЭМа из коробки. Но взгляните на код. Он с первого взгляда может демотивировать неподготовленного разработчика: Код из публичного репозитория project-stub. Код конфига ENB явно будет сложным для тех, кто только начинает использовать БЭМ.  В документации представлены готовые настройки сборщика, и их вполне можно использовать, не вникая в детали сборки. Но что если вам как и мне хотелось бы иметь полное представление о том, что происходит с проектом во время сборки? В документации БЭМ хорошо объясняется процесс сборки в теории, однако практических примеров немного и они не всегда подходят для наглядного понимания процесса. Чтобы решить эту проблему я попробую собрать элементарный БЭМ-проект с помощью Webpack. До этого я упоминал, что разделение кода и организация сборки упрощают работу с проектом. В примере ниже мы обеспечим разделение кода с помощью БЭМ и его сборку при помощи Webpack. Мы хотим получить наипростейший конфиг, логика сборки должна быть линейной и интуитивно понятной. Давайте соберём страницу с одним БЭМ-блоком, у которого будут две технологии: CSS и JS.  Можно написать HTML-код с одним DIV с классом "block" и вручную подключить все его технологии. Используя БЭМ-именование классов и соответствующую файловую структуру, мы не нарушаем принципы методологии. У меня получилось вот такое дерево проекта: В первой строке упоминается уровень переопределения “desktop”. В терминологии БЭМ, уровни переопределения — директории, которые содержат собственные реализации блоков. При сборке проекта в итоговый бандл попадают реализации со всех уровней переопределения в определённом порядке.  Например, у нас есть уровень переопределения "desktop", в котором хранятся реализации блоков для настольных устройств. Если нам понадобится дополнить проект вёрсткой для мобильных устройств, нам будет достаточно создать новый уровень переопределения "mobile" и наполнить его новыми реализациями тех же блоков. Удобство такого подхода в том, что на новом уровне переопределения нам не нужно будет дублировать код, уже существующий в "desktop", так как он подключится автоматически. Перед вами конфиг Webpack: Здесь мы указываем файл /pages/index.js как входную точку, добавляем загрузчики для стилей CSS и копируем /pages/index.html в /dist/index.html. В примере использован один уровень переопределения и один блок. Задача — собрать страницу так, чтобы к ней были подключены технологии (css, js) нашего блока. Для подключения технологий воспользуемся require(): Запустим Webpack и посмотрим, что получилось. Откроем index.html из папки ./dist:  Стили блока подгрузились, javascript успешно отработал. Теперь к нашему проекту по праву можно добавить заветные буквы "БЭМ". Прежде всего БЭМ создавался для работы с большими проектами. Давайте представим, что наш дизайнер постарался и на страничке теперь находится не один блок, а сто. Действуя по предыдущему сценарию, мы будем вручную подключать технологии каждого блока, используя require(). То есть в index.js появится как минимум сто дополнительных строк кода.  Лишние строки кода, которых можно было избежать, — это плохо. Неиспользуемый код — ещё хуже. Что если на нашей странице будет всего 10 из имеющихся блоков, или 20, или 53? У разработчика появится дополнительная работа: ему придется фокусировать внимание на том, какие именно блоки используются на странице, а также подключать и отключать их вручную, чтобы избежать лишнего кода в итоговом бандле.  К счастью, эту работу можно поручить Webpack. Оптимальный алгоритм действий для автоматизации этого процесса:  Для начала я решил проверить, нет ли готовых загрузчиков для данной задачи. Модуля, который предоставлял бы весь нужный функционал в одном флаконе, я не обнаружил. Но наткнулся на bemdecl-to-fs-loader, который преобразует декларации БЭМ в выражения require(). Он основывается на уровнях переопределения и технологиях, которые имеются в файловой структуре проекта.  Не хватает одного звена — преобразования HTML в массив БЭМ-сущностей. Эту задачу решает модуль html2bemjson.  bemjson не является декларацией, поэтому предварительно преобразуем его в формат decl для передачи в bemdecl-to-fs-loader. Для этой задачи используем модуль из SDK: bemjson-to-decl. Так как это обычные NodeJS-модули, а не загрузчики Webpack, придется сделать загрузчик-обертку. После этого мы сможем использовать их для преобразований в Webpack.  Получаем такой код загрузчика: Чтобы упростить установку загрузчика и сэкономить время в дальнейшем, я загрузил модуль на NPM. Давайте установим загрузчик в наш проект и внесём изменения в конфигурацию Webpack: Параметр levels загрузчика bemdecl-to-fs-loader указывает, какие уровни переопределения использовать и в каком порядке. В extensions даны расширения файлов-технологий, которые используются в нашем проекте. В итоге вместо подключения технологий вручную, мы подключаем лишь HTML-файл. Все необходимые преобразования будут выполнены автоматически.  Давайте заменим содержимое index.js строкой: Теперь запустим Webpack. При сборке выводится строка: Это значит, что формирование декларации прошло успешно. Смотрим непосредственно вывод Webpack:  Мы получили результат, идентичный предыдущему, с той разницей, что все технологии блока подключились автоматически. Сейчас нам достаточно добавить в HTML БЭМ-именованный класс, подключить этот HTML с помощью require() и создать соответствующий каталог с технологиями для подключения. Итак, у нас есть файловая структура, которая соответствует методологии БЭМ, а также механизм автоматического подключения технологий блоков.  Абстрагируясь от механизмов и сущностей методологии, мы создали предельно простой, но эффективный конфиг Webpack. Надеюсь, данный пример поможет всем, кто начинает своё знакомство с БЭМ, лучше понять базовые принципы сборки БЭМ-проектов.