Skip to content

Instantly share code, notes, and snippets.

@dima117
Last active August 21, 2016 20:19
Show Gist options
  • Save dima117/27b142bcbb9b90ef92b80bd6f1cd63fa to your computer and use it in GitHub Desktop.
Save dima117/27b142bcbb9b90ef92b80bd6f1cd63fa to your computer and use it in GitHub Desktop.

Привет! Меня зовут Дмитрий Андриянов. Я работаю разработчиком интерфейсов в Яндекс.Директе, а до этого 9 лет был full-stack разработчиком сайтов на платформе .NET.

Я расскажу вам способ, как легко и просто использовать БЭМ в проектах на ASP.NET MVC. БЭМ - не тот, который "странные правила именования css-селекторов", а настоящий - с уровнями переопределения и общими шаблонами для клиента и сервера.

[картинка: ASP.NET + b_ = сердечко]

[Кнопка:Добро пожаловать под кат!]

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

Чтобы методология (любая) приносила пользу, нужны инструменты, гарантирующие соблюдение её правил. Представьте, сколько пользы было бы от методологии ООП, если бы не было языков программирования, реализующих ее... Правильно, очень мало!

Для БЭМ тоже написаны инструменты. Они очень крутые, много лет работают в продакшене и Яндекс всячески их пиарит, но, к сожалению, не все могут их использовать. Дело в том, что БЭМ-инструменты написаны на JavaScript и для их работы нужен node.js. Это означает, что для пользования ими на других платформах нужно написать (и поддерживать) дополнительный интеграционный код. Кроме того, если код для node.js работает как отдельный сервис, его нужно администрировать. Всё вместе это образует серьезный потенциальный источник проблем. А так как без инструментов принципы БЭМ работают только в css, большинство людей в результате считают, что БЭМ - это просто правила именования css-селекторов.

тематическое соотношение постов о БЭМ тематическое соотношение постов о БЭМ

БЭМ в .NET

Мы очень хотели бы изменить ситуацию и сделать БЭМ-инструменты более доступными. В Яндексе периодически проходят внутренние хакатоны по БЭМ-инструментам и на одном из них мы взяли задачу - запилить БЭМ-инфраструктуру для .NET. Платформу .NET выбрали потому, что на тот момент уже были некоторые наработки в этом направлении.

Цель была - написать тот самый интеграционный код, который вы могли бы добавить в свой проект и сразу начать использовать БЭМ. В результате мы опубликовали в NuGet пакет System.Web.Bem, содержащий всё необходимое для БЭМ-разработки на .NET. Чтобы установить его, наберите в консоли менеджера пакетов:

PM> Install-Package System.Web.Bem -Pre

При установке в проект пакета System.Web.Bem:

  • добавляется папка Bem с файловой структурой БЭМ проекта;
  • из npm ставится сборщик БЭМ-проектов enb и настройки для сборки БЭМ-бандлов при компиляции ASP.NET MVC проекта;
  • подключается .NET библиотека System.Web.Bem для серверной шаблонизации во время работы приложения.

А теперь обо всем подробнее...

Внимание! Всё нижесказанное справедливо для .NET 4.5.2 и ASP.NET MVC 5. На компьютере разработчика должен быть установлен node.js. Для работы приложения на сервере устанавливать node.js нет необохдимости.

Сборка

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

Специальная программа-сборщик должна склеить все нужные блоки в один бандл в нужном порядке (собирается отдельный бандл для каждой технологии). Иногда при этом выполняется дополнительная обработка кода блоков (препроцессоры CSS, babel для конвертации ES6 в ES5, минимизация). Во время работы приложения бандл шаблонов используется для формирования html (на сервере и клиенте), бандлы js и css подключаются на страницы и используются на клиенте.

Декларация бандла - это файл со списком блоков, которые должны попасть в бандл. На основе декларации сборщик собирает бандлы, учитывая при этом зависимости блоков и уровни переопределения. Файл декларации обычно имеет расширение .bemdecl.js и примерно такое содержимое:

exports.blocks = [
  { name: 'block1' },
  { name: 'block2' }
];

Для сборки БЭМ-бандлов в .NET проекте мы выбрали ENB - это наиболее актуальный БЭМ-сбощик, который успешно используется во многих веб-проектах Яндекса. Во время установки NuGet-пакета System.Web.Bem в ваш проект будет также установлен сборщик ENB (из npm) и будут добавлены необходимые настройки для него. Кроме того, будет настроен автоматический запуск ENB во время сборки всего проекта через MsBuild. Таким образом, когда вы собираете свой проект в Visual Studio, вместе с компиляцией c# кода будет запущена и сборка БЭМ-бандлов.

Структура проекта

При установке пакета System.Web.Bem в проекте будет создана папка Bem для размещения в ней файлов БЭМ-файлов. По умолчанию предлагается следующая структура файлов:

<Project root>                  // корневая папка проекта
├─ Bem                          // папка БЭМ-проекта
│  ├─ .enb
│  │  └─ make.js                // настройки сборщика enb
│  ├─ desktop.blocks            // уровень переопределения, внутри находятся блоки
│  │  ├─ block-1 
│  │  ├─ block-2 
│  │  │  ... 
│  │  └─ block-n 
│  │     ├─ block-n.bemhtml.js  // реализация блока block-n в технологии bemhtml.js (шаблоны)
│  │     ├─ block-n.css         // реализация блока block-n в технологии css 
│  │     │  ...                 // ...
│  │     └─ block-n.js
│  ├─ desktop.bundles           // папка с бандлами проекта
│  │  ├─ bundle-1 
│  │  ├─ bundle-2 
│  │  │  ... 
│  │  └─ bundle-n 
│  │     └─ bundle-n.bemdecl.js // декларация бандла bundle-n 
│  └─ levels.js                 // список уровней переопределения
│  ...
├─ Controllers                  // Controllers, Models, Views - стандартные папки ASP.NET MVC
├─ Models
├─ Views
│  ...
├─ package.json                 // конфиг npm
└─ Web.config                   // конфиг вашего приложения

Обратите внимание, декларации бандлов находятся в папке /Bem/desktop.bundles, каждый бандл в своей папке. Имя файла декларации - такое же, как имя бандла, а расширение - .bemdecl.js. Сборка настроена так, что сначала в проекте ищутся все декларации бандлов, а потом для каждой из них собираются бандлы технологий. Таким образом, после сборки в папке каждого бандла вы увидите примерно такую картину:

<Project root>
├─ Bem
│  ├─ ...
│  └─ desktop.bundles
│     ├─ default 
│     │  ├─ default.bemdecl.js  // декларация бандла
│     │  ├─ default.bemhtml.js  // бандл с шаблонами 
│     │  ├─ default.js          // бандл с клиентским кодом 
│     │  └─ default.css         // бандл со стилями 
│     │  └─ ...                 // бандлы других технологий
│     └─ ...
└─ ...

Шаблонизация

BEMHTML - это шаблонизатор, который удобно использовать в БЭМ проектах.

  • В отличие от других шаблонизаторов, где шаблоны являются просто текстом со вставками кода, шаблоны BEMHTML имеют структуру. Благодаря этому есть возможность переопределить любую часть шаблона.
  • BEMHTML работает в терминах БЭМ (т.е. он знает, что ваше приложение состоит из блоков с элементами и модификаторами) и генерирует в верстке правильные названия классов. (Вы же не думали, что в Яндексе пишут эти страшные названия классов вручную?)
  • Логика в шаблонах пишется на JavaScript. Так как в Яндексе на стороне сервера есть node.js, одни и те же шаблоны используются на сервере и на клиенте.

Если хотите больше узнать про BEMHTML, прочитайте документацию и поиграйтесь в online-песочнице. Есть также отличный вебинар на эту тему, обязательно посмотрите его!

Шаблонизация BEMHTML на стороне сервера

Одна из наиболее полезных возможностей БЭМ - использование одних и тех же шаблонов на сервере и на клиенте. Поэтому одной из основных наших задач было сделать эту возможность доступной в .NET проектах. Для использования BEMHTML-шаблонов на стороне сервера (а вы же помните, что у них внутри JavaScript?) мы написали специальную .NET библиотеку, которая внутри .NET процесса запускает node.js и выполняет в нем оригинальный код шаблонизатора BEMHTML. Для запуска node внутри .NET используется библиотека EDGE.js.

Чтобы на стороне сервера сгенерировать HTML по BEMHTML-шаблону, просто верните из метода контроллера экземпляр класса BemhtmlResult, передав ему в конструктор нужный bemjson.

using System.Web.Bem;
...
public class DefaultController : Controller
{
  public ActionResult Index()
  {
    var myData = ...
    return new BemhtmlResult(new { block = "p-index", data = myData });
  }
}

Если нужно внутри Razor-шаблона вставить БЭМ-блок, используйте хелпер @Html.Bem.

@Html.Bem(new { block = "my-block", data = Model })

Шаблоны берутся из бандла технологии bemhtml.js, который формируется при сборке. Если в приложении несколько бандлов с шаблонами, вы можете настроить в файле Web.config, какие бандлы будут использоваться для каких запросов. Подробнее читайте в документации.

Использование на клиенте

Шаблонизатор BEMHTML написан на JavaScript и он прекрасно работает в браузере. Для использования BEMHTML на стороне клиента подключите на страницу сформированный во время сборки бандл с шаблонами и вызовите метод apply глобальной переменной BEMHTML (она описана в бандле). Метод apply принимает единственный параметр - bemjson, который нужно отшаблонизировать. Например:

var bemjson = { block: 'quote', content: 'Пришел, увидел, отшаблонизировал.' };
var html = BEMHTML.apply(bemjson);

// html → <div class="quote">Пришел, увидел, отшаблонизировал.</div>

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

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

{
  tech: 'js',
  shouldDeps: [
    { block: 'B', tech: 'bemhtml.js' }
  ]
}

Этот фрагмент означает, что реализация блока A в технологии js зависит от реализации блока B в технологии bemhtml.js. Другими словами, мы говорим, что в клиентском коде блока A мы будем использовать BEMHTML-шаблон блока B.

Клиентский фреймворк i-bem

Для удобной разработки клиентской части приложения в терминах БЭМ в Яндексе написали собственный JavaScript-фреймворк i-bem. Из документации:

i-bem.js позволяет:

  • разрабатывать веб-интерфейс в терминах блоков, элементов, модификаторов;
  • описывать логику работы блока в декларативном стиле — как набор состояний;
  • легко интегрировать JavaScript-код с BEMHTML- или BH-шаблонами и CSS в стиле БЭМ;
  • гибко переопределять поведение библиотечных блоков.

Для i-bem есть отличная документация, в которой подробно описаны все его возможности и особенности. Обязательно ознакомьтесь с ней!

i-bem реализован в виде БЭМ-блока и вохдит в состав библиотеки bem-core. Для удобстав подключения к ASP.NET MVC проектам мы выложили bem-core в NuGet. Просто установите пакет bem-core через менеджер пакетов и подключите его папку с блоками как уровень переопределения.

PM> Install-Package bem-core

Кроме фреймворка i-bem, в bem-core есть еще много полезных блоков. Их полный список и описание - на страничке bem-core в GitHub.

bem-components

Bem-components - это open source библиотека визуальных компонентов, разработанная по методологии БЭМ. Она содержит большое количество элементов интерфейса: там есть различные кнопки, поля ввода, всплывающие окна, меню и тому подобное. Все компоненты очень хорошо проработаны, покрыты тестами и поддерживают темы оформления. Есть даже мнение, что они даже лучше, чем Bootstrap ;)

Bem-components мы тоже выложили в nuget. Просто установите пакет bem-components через менеджер пакетов и добавьте уровни переопределения.

PM> Install-Package bem-components

Попробуйте

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment