— Сначала вы его отрицаете, потом вы его ненавидите, а потом вы не можете без него жить.
из доклада Артема Курбатова «БЭМ: мастер-класс»
Методология БЭМ существует достаточно долго и принята на вооружение в Google, EPAM Systems, BBC, Альфа-Банке. При этом она все еще вызывает беспокойство у типичного разработчика и менеджера проектов среднего звена.
У некоторых смельчаков изучение БЭМ не ушло дальше ограничения возможностей CSS для получения более предсказуемых результатов. И хотя БЭМ давно вышел за пределы верстки, до сих пор на вопрос «Знаете ли вы БЭМ?» можно услышать: «Конечно, это про подчеркивания в классах».
Если ваше представление о БЭМ близко к этому, я отвечу вам словами работодателя при приеме на работу новоиспеченного выпускника: «Забудьте о том, что вы слышали о БЭМ ранее». Методология БЭМ настолько интересна, насколько большинству о ней ничего не известно. Чтобы понять всю прелесть БЭМ, необходимо иметь представление обо всех технологиях, библиотеках, фреймворках и инструментах, которые БЭМ предоставляет. Изучите их, оставайтесь инопланетянином, ребенком, который удивляется тому, с чем взрослые смирились.
Оглавление
- Используемые обозначения
- Используемые технологии
- Приложение Hello, World
- Приложение Social Services Search Robot
Что для меня БЭМ?
Наверняка вы слышали истории, как дерзкие вундеркинды, закрывшись в гараже, изобрели очередной стартап. Первые успехи позволили им привлечь инвестиции и выйти на рынок с потрясающим продуктом. Как это им удалось, как удалось выдержать пиковые нагрузки и не погрязнуть в вечном рефакторинге? Как надо, чтобы не как обычно?
БЭМ — это лайфхак для стартаперов. По сравнению со многими другими фреймворками и технологиями начало работы с БЭМ требует определенных усилий, но это окупается архитектурой, обеспечивающей устойчивую расширяемость. Во все технологии, фреймворки и библиотеки БЭМ изначально заложены принципы декларативного подхода. И именно это делает их такими непонятными на первый взгляд и любимыми в итоге.
Прочитав данную статью вы не постигните дзен БЭМ, но точно сможете ответить взрослым, что научились создавать полноценные динамические проекты по БЭМ, используя не только CSS. И если завтра ваше приложение постигнет участь в +10 К пользователей в сутки, будьте спокойны — у вас останется времени отметить это событие.
Сегодня мы расскажем о новом шаблонном репозитории для динамических проектов bem-express, который не только позволяет развернуть БЭМ-проект в один клик, но и делает автоматическую пересборку проекта и перезагрузку браузера. На его основе разработаем динамическое приложение и опишем процесс взаимодействия различных БЭМ-технологий. Мы сознательно не будем рассматривать вопросы верстки и клиентского JavaScript, чтобы избежать участи «подчеркивания в классах».
Что мы будем разрабатывать?
Поисковое приложение Social Services Search Robot (сокр. SSSR), которое по запросу покажет последние твиты и видео с YouTube.
Будем использовать:
- фреймворк i-bem.js;
- шаблонизатор bem-xjst;
- технологию для описания зависимостей DEPS;
- Express.js;
- YouTube Data API;
- Twitter Search API.
Для начала потребуется установить:
Важно! Пользователям операционной системы Windows необходимо дополнительно установить Git Bash.
Используемые обозначения
Чтобы статья получилась ярче, мы немного порисуем:
- — директория;
- — файл;
- — создать директорию;
- — создать файл;
- — отредактировать файл.
Используемые технологии
В БЭМ нет разделения технологий на главные и второстепенные. Есть набор, а выбор применения определяется индивидуально:
- BEMDECL — технология для описания деклараций в БЭМ.
- DEPS — технология для описания зависимостей в БЭМ.
- BEMTREE — шаблонизатор преобразующий данные в BEMJSON.
- BEMHTML — шаблонизатор преобразующий BEMJSON в HTML.
- i-bem.js — JavaScript-фреймворк для БЭМ.
Подробнее о BEMJSON-формате входных данных.
Давайте рассмотрим их подробнее.
BEMDECL
Определяет список БЭМ-сущностей для страницы.
Такой список в БЭМ называется декларацией. Задача декларации — определить, что и в каком порядке подключать в сборку.
Декларации описываются в файлах с расширением .bemdecl.js
.
Пример
exports.blocks = [
{ name: 'page' },
{ name: 'header' },
{ name: 'body' },
{ name: 'footer' }
];
Когда количество блоков переходит рубеж «легко запомнить», возникает проблема их перечисления в нужном порядке. Поэтому обычно декларируют какой-то определенный блок, который следует рассматривать как центральную «точку входа».
Все остальные БЭМ-сущности попадают в сборку по зависимостям.
DEPS
Определяет зависимости между БЭМ-сущностями, которые разнесены по файловой структуре проекта и не отражены в декларации.
Зависимости описываются в виде JavaScript-объекта в файлах с расширением .deps.js
.
Пример
/* page зависит от header */
({
block: 'page',
shouldDeps: [
{ block: 'header' }
]
})
Название технологии происходит от английского слова dependence и обозначает желание подключить в сборку какую-то БЭМ-сущность. Изучающие БЭМ порой забывают о декларативности технологий и недоумевают: почему для описанного в шаблоне блока, не собираются его стили и скрипты.
Помните: когда вы описываете шаблон (BEMHTML или BEMTREE) с каким-то блоком внутри (дочерний узел), вы просто добавляете новый HTML-элемент. Чтобы стили и скрипты этого блока попали в сборку, необходимо описать зависимость от него.
Например, для того чтобы добавить в сборку блоки header
, body
и footer
, необходимо описать зависимость от них:
/* page зависит от header, body, footer */
({
block: 'page',
shouldDeps: [
'header',
'body',
'footer'
]
})
Нижеследующая схема показывает логику сборки по зависимостям:
index(DECL) # Декларация блока page
|
L--> page(DEPS) # Зависимость блока page от header, body, footer
|
+--> header(DEPS)
| |
| L--> ...
|
+--> body(DEPS)
| |
| L--> ...
|
L--> footer(DEPS)
|
L--> ...
BEMTREE
Является частью шаблонизатора bem-xjst и преобразует данные в BEMJSON.
Шаблоны описываются в BEMJSON-формате в файлах с расширением .bemtree.js
.
Вход и выход шаблонизатора:
BEMHTML
Является частью шаблонизатора bem-xjst и преобразует BEMJSON-описание страницы в HTML.
Шаблоны описываются в файлах с расширением .bemhtml.js
.
Вход и выход шаблонизатора:
i-bem.js
Клиентский JavaScript-фреймворк для веб-разработки в рамках БЭМ-методологии.
JavaScript-код описывается в файлах с расширением .js
.
Позволяет:
- разрабатывать веб-интерфейс в терминах блоков, элементов, модификаторов;
- описывать логику работы блока в декларативном стиле — как набор состояний;
- легко интегрировать код JavaScript с BEMHTML-шаблонами и CSS;
- гибко переопределять поведение библиотечных блоков.
Приложение Hello, World
У программистов есть традиция: начинать программирование на новом языке или фреймворке с приложения Hello, World. Приложение обычно выводит слова «Hello, World» в выходной поток, демонстрируя тем самым, что оно запускается и выполняет операции ввода/вывода.
Давайте создадим его, а затем расширим до желаемого SSSR.
Нам потребуется локальная копия шаблонного репозитория bem-express. Ее можно сделать с помощью Git.
Примечание. Для пользователей OS X или Linux все команды выполняются в терминале. Пользователям Windows потребуется Git Bash. Убедитесь, что Git Bash запущен от имени администратора.
Шаблонный репозиторий
При решении задач по разработке динамических приложений в рамках БЭМ создан шаблонный репозиторий bem-express. Он содержит необходимый минимум конфигурационных файлов и решает целый класс задач, таких как сборка проекта, настройка линтеров, подключение библиотек и др.
В него по умолчанию подключены основные БЭМ-библиотеки:
Быстрый старт
Чтобы создать приложение Hello, World:
Склонируйте bem-express:
git clone https://github.com/bem/bem-express.git sssr-project
Примечание. В данном примере используется
bem-express
версии 2.00.
Перейдите в директорию проекта:
cd sssr-project
Удалите историю версионирования исходного репозитория:
rm -rf .git
Инициализируйте собственный Git-репозиторий:
git init
Установите зависимости:
npm install
Примечание. Не используйте права суперпользователя
root
при установке npm-зависимостей.
Соберите проект и запустите сервер:
npm run dev
Примечание. За сборку отвечает ENB.
При запуске приложения в терминале выводится сообщение о том, что сервер выполняется на порте 3000:
Server is listening on 3000
.
Примечание. Если порт
3000
используется другой программой, его можно переназначить. Например, на8000
:
Способ 1. Изменение значения при запуске приложения.
PORT=8000 npm run dev
Способ 2. Изменение значения по умолчанию в файлеserver/config.js
.
defaultPort: 8000,
На компьютере запустился:
- сервер — отвечает за обработку динамических данных;
- nodemon — следит за изменениями в файловой структуре и перезапускает сервер;
- chokidar — следит за изменениями в файлах директорий
*.blocks/
и перестраивает структуру проекта; - livereload — обновляет страницу в браузере.
Откройте браузер и введите адрес localhost:3000.
Должна открыться страница со следующим контентом:
Index page content footer content
Примечание. Если при запуске приложения в Windows, выводится уведомление от Брандмауэра:
- Отключите опцию Общественные сети (Public Network).
- Установите опцию Частные сети (Private Network).
- Разрешите доступ.
Откройте файл
server/index.js
и внесите следующие изменения (см. комментарии) в код начинающегося строкойapp.get('/', function(req, res)
:
/** * Функция обрабатывает все GET-запросы с главной страницы приложения * @function * @param {object} req - Запрос. * @param {object} res - Ответ. */ app.get('/', function(req, res) { var hello = 'Hello'; // Инициализируем переменную `hello` var world = 'World'; // Инициализируем переменную `world` render(req, res, { view: 'page-index', title: 'Main page', meta: { description: 'Page description', og: { url: 'https://site.com', siteName: 'Site name' } }, hello: hello, // Передаем переменную `hello` в `this.data.hello` world: world // Передаем переменную `world` в `this.data.world` }) });
Откройте файл
common.blocks/page-index/page-index.bemtree.js
и замените его содержимое на следующее:
block('page-index').content()(function() { // Получаем данные из глобального объекта `this` var data = this.data; // Возвращаем полученные данные: `data.hello: 'Hello'`, `data.world: 'World'` return data.hello + ', ' + data.world; });
После сохранения сервер автоматически перезапустится и контент страницы изменится на:
Hello, World footer content
Приложение Hello, World готово.
Не получилось?
Если при создании приложения возникли сложности, поищите решение на форуме. Если готового ответа не нашлось, задайте вопрос.
Приложение Social Services Search Robot
Собственно мы дошли до шага разработки приложения SSSR. Напомню, что по запросу приложение будет выводить последние твиты и видео с YouTube.
Сразу забежим в недалекое будущее — выглядеть приложение будет так:
Схема работы приложения
Шаг 1. Запрос
Пользователь отправляет запрос на сервер.
Шаг 2. Получение данных
Приложение обращается за данными к Twitter Search API и YouTube Data API в соответствии с полученным запросом.
Шаг 3. BEMTREE-шаблонизация
Приложение передает полученные данные BEMTREE-шаблонизатору, который преобразует данные в BEMJSON.
Шаг 4. BEMHTML-шаблонизация
Приложение передает BEMJSON BEMHTML-шаблонизатору, который преобразует BEMJSON в HTML.
Шаг 5. Отправка результата пользователю
Приложение возвращает результат (HTML-страницу) пользователю.
Используемые модули Node
Базовая реализация Node остается настолько простой, насколько это возможно. Вместо того, чтобы встраивать все возможные компоненты прямо в Node, разработчики предоставляют дополнительную функциональность в виде отдельных модулей (пакетов).
Система модулей Node построена по образцу системы CommonJS, механизма создания взаимодействующих модулей. Центральное место в системе занимает контракт, который должен выполняться разработчиками, чтобы их модули нормально взаимодействовали с другими.
Все пакеты установленные с помощью менеджера пакетов npm находятся в директории node_modules
.
Подключение модулей происходит при помощи команды require
. Если пакет установлен с использованием npm, указывать путь не нужно. Достаточно указать имя:
var express = require('express');
При подключении собственного локального модуля, необходимо указать к нему путь:
var someModule = require('./somefolder/somemodule');
Важной особенностью любого модуля является то, что он должен быть рассчитан на взаимодействие с Node. Для этого модуль нужно экспортировать с помощью module.exports
:
module.exports = {
// some module
};
Для работы приложения потребуются следующие модули:
- express — предоставляет большую часть функциональности, необходимой для построения веб-приложения;
- passport — предоставляет различные стратегии аутентификации для приложений Node.js;
- passport-youtube-v3 — предоставляет механизм аутентификации на Youtube посредством аккаунта Youtube и токенов OAuth 2.0;
- twitter — клиентская библиотека для работы с Twitter REST API;
- googleapis — клиентская библиотека для работы с Google REST API;
- moment — JavaScript библиотека для синтаксического анализа, валидации и форматирования дат.
Установить их можно одной командой:
npm install express passport passport-youtube-v3 twitter googleapis moment --save
Подготовка структуры проекта
Прежде чем начать писать код, немного изменим структуру взятого за основу приложения Hello, World.
Изменения для:
Изменения для статических файлов
Директория static
Создайте поддиректорию
images
.
- Перенесите фавиконку в поддиректорию
images
.
Директория common.blocks
Отредактируйте файл
root/root.bemtree.js
.
Измените:
favicon: '/favicon.ico',
На:
favicon: '/images/favicon.ico',
Директория server
Отредактируйте файл
index.js
.
Измените:
.use(favicon(path.join(staticFolder, 'favicon.ico')))
На:
.use(favicon(path.join(staticFolder, '/images/favicon.ico')))
Изменения для серверного кода
Директория server
Создайте поддиректории:
controllers
— контроллеры;helpers
— хелперы;middleware
— модули промежуточного звена.
Создайте пустые
JS
-файлы для будущих модулей:
app.js
— модуль монтирования промежуточных модулей (делает их доступными в приложении);auth.js
— модуль аутентификации на YouTube;routes.js
— модуль маршрутизации веб-запросов.
Добавьте следующий код в файл
app.js
.
Добавьте следующий код в файл
routes.js
.
Измените расширение файла
config
:
config.js
—>config.json
Отредактируйте файл
config.json
.
Измените:
module.exports = { staticFolder: 'static', defaultPort: 3000, cacheTTL: 30000, sessionSecret: 'REPLACE_ME_WITH_RANDOM_STRING' };
На:
{ "staticFolder": "static", "defaultPort": 3000, "cacheTTL": 30000, "sessionSecret": "REPLACE_ME_WITH_RANDOM_STRING" }
Измените весь текущий контент файла
index.js
на следующий.
Примечание. В
index.js
остается только функциональность, отвечающая за запуск приложения и прослушивание запросов на порте.
Директория controllers
Создайте пустой
JS
-файл:
index.js
— контроллер обработки запросов и рендеринга HTML.
- Добавьте следующий код в файл
index.js
.
Директория helpers
Создайте пустые
JS
-файлы:
index.js
— входная точка для хелперов;twitter.js
— модуль-хелпер для работы с Twitter Search API;youtube.js
— модуль-хелпер для работы с YouTube Data API.
Директория middleware
Создайте пустой
JS
-файл:
auth.js
— модуль проверки прохождения аутентификации на YouTube.
Получение OAuth-токенов
Сервисы Twitter и Google хранят различные данные пользователей — твиты, видео на Youtube, письма в Почте, фотографии и так далее. Чтобы обеспечить удобный доступ к этим данным из других приложений или сторонних сервисов, они используют открытый протокол авторизации OAuth 2.0.
Согласно протоколу, разработчик регистрирует приложение на OAuth-сервере и запрашивает доступ к определенным данным. Авторизованный пользователь разрешает или запрещает его.
Получение OAuth-токена для Twitter
Twitter предлагает приложениям возможность выдавать аутентифицированные запросы от имени самого приложения.
С чего начать?
- Изучите документацию.
- Зарегистрируйте приложение и получите ключи (Consumer Key, Consumer Secret).
- Установите Postman любым удобным для вас способом.
- Закодируйте строку
Consumer Key:Consumer Secret
методом Base64. - Получите OAuth-токен в обмен на код.
Используйте полученные токен и ключи в запросах к Twitter Search API.
Примечание. Postman поможет получить OAuth-токен с помощью POST-запроса в обмен на код, полученный методом Base64.
Как закодировать строку?
Чтобы закодировать строку методом Base64:
Сформируйте строку вида:
Consumer Key:Consumer Secret
.
Пример
xvz1evFS4wEEPTGEFPHBog:L8qq9PZyRg6ieKGEKhZolGC0vJWLw8iEJ88DRdyOg
Примечание. Получить ключи Consumer Key и Consumer Secret можно, перейдя на вкладку Keys and Access Tokens вашего приложения.
- Запустите терминал или Git Bash.
- Выполните команду
echo -n "xvz1evFS4wEEPTGEFPHBog:L8qq9PZyRg6ieKGEKhZolGC0vJWLw8iEJ88DRdyOg" | base64
. Скопируйте полученный код.
Пример
eHZ6MWV2RlM0d0VFUFRHRUZQSEdFS2hab2xHQzB2SldMdzhpRUo4OERSZHlPZw==
Примечание. Если возникли сложности, воспользуйтесь онлайн-ресурсом base64encode.org.
Как получить OAuth-токен в обмен на код?
Чтобы получить токен в обмен на код:
Запустите Postman.
Примечание. По умолчанию открывается вкладка, в которой необходимо сформировать POST-запрос к OAuth-серверу Twitter.
- Выберите тип запроса POST.
- Введите адрес сервера
https://api.twitter.com/oauth2/token
. - Перейдите на вкладку Headers.
Введите в поле Key заголовок
Authorization
со значением (поле Value)Basic <закодированная строка Consumer Key:Consumer Secret>
.
Пример
Authorization: Basic eHZ6MWV2RlM0d0VFUFRHRUZQSEdFS2hab2xHQzB2SldMdzhpRUo4OERSZHlPZw==
Примечание. Basic указывает на базовый метод авторизации.
Введите второй заголовок
Content-Type
со значениемapplication/x-www-form-urlencoded;charset=UTF-8
.
Пример
Content-Type: application/x-www-form-urlencoded;charset=UTF-8
- Перейдите на вкладку Body.
- Выберите опцию
x-www-form-urlencoded
. - Введите в поле Key тело запроса
grant_type
со значениемclient_credentials
. Нажмите кнопку Send.
OAuth-сервер вернет токен в JSON-формате:
{ "token_type": "bearer", "access_token": "AAAAAAAAAAAAAAAAAAAAAA%2FAAAAAAAAAA%3DAAAAAAAAAAAAAAAAAA" }
Важно! Сохраните полученные токен и ключи (Consumer Key и Consumer Secret). Они потребуются для конфигурационного файла приложения.
Получение OAuth-токена для Google
Google предлагает приложениям возможность выдавать аутентифицированные запросы от имени самого приложения.
Примечание. За получение и обновление OAuth-токена с помощью POST-запроса в обмен на код авторизации отвечает модуль passport-youtube-v3.
С чего начать?
- Изучите документацию.
- Зарегистрируйте приложение и получите Client ID и Client Secret.
- Укажите callback URL (в нашем случае это
http://localhost:3000
) в учетной записи вашего приложения. - Используйте полученные Client ID и Client Secret в запросах к YouTube Data API.
Важно! Сохраните полученные ключи (Client ID и Client Secret). Они потребуются для конфигурационного файла приложения.
Конфигурация приложения
После того как все ключи и токены получены, их необходимо добавить в конфигурационный файл приложения:
Добавьте в файл
server/config.json
полеservices
.
"services": { "twitter": { "consumer_key": "", "consumer_secret": "", "bearer_token": "" }, "youtube": { "client_id": "", "client_secret": "", "redirect_url": "http://localhost:3000" } }
- Заполните одноименные поля полученными данными.
Скройте файл
server/config.json
от системы контроля версий Git, чтобы случайно не добавить личные ключи в репозиторий файлов.
# файл .gitignore server/config.json
Работа с Twitter Search API
Twitter Search API позволяет найти последние или популярные твиты, опубликованные на сайте Twitter.com за последние 7 дней.
Для успешного вызова API необходимо сделать следующие изменения:
Директория controllers
- Измените весь текущий контент файла
index.js
на следующий.
Директория helpers
Добавьте в файл
index.js
следующий контент:
module.exports = { twitter: require('./twitter') };
- Добавьте следующий код в файл
twitter.js
.
Работа с YouTube Data API
YouTube Data API позволяет найти видеоролики, опубликованные на сайте Youtube.com. По умолчанию в набор результата поиска включены следующие ресурсы: видео, каналы, списки воспроизведения.
Для успешного вызова API необходимо сделать следующие изменения:
Директория server
Добавьте следующий код в файл
auth.js
.
Отредактируйте файл
routes.js
.
Измените:
var router = require('express').Router(), controllers = require('./controllers'); router .get('/ping/', function(req, res) { res.send('ok'); }) .get('/', controllers.getContent); module.exports = router;
На:
var router = require('express').Router(), controllers = require('./controllers'), passportYouTube = require('./auth'), middleware = require('./middleware/auth'), isAuthenticated = middleware.isAuthenticated; router .get('/auth/youtube', passportYouTube.authenticate('youtube')) .get('/auth/youtube/callback', passportYouTube.authenticate('youtube', { failureRedirect: '/error', failureFlash: true }), (req, res) => { res.redirect('/'); }) .get('/', isAuthenticated, controllers.getContent); module.exports = router;
Директория controllers
- Измените весь текущий контент файла
index.js
на следующий.
Директория helpers
Добавьте в файл
index.js
следующий контент (см. комментарий):
module.exports = { twitter: require('./twitter'), youtube: require('./youtube') // Подключаем модуль `youtube.js` };
- Добавьте следующий код в файл
youtube.js
.
Директория middleware
Добавьте в файл
auth.js
следующий контент:
module.exports = { isAuthenticated: function(req, res, next) { if (req.isAuthenticated()) return next(); return res.redirect('/auth/youtube'); } };
Верстка
Мы сознательно не рассматривали вопросы верстки и клиентского JavaScript. Это привело бы к большему объему, а, значит, и к меньшей практической ценности данной статьи.
Процесс верстки сведен к следующим шагам:
- Удалите все блоки из директории
common.blocks
. - Склонируйте следующие блоки в директорию
common.blocks
. - Добавьте logo.svg в директорию
static/images
. - Перезапустите сервер:
npm run dev
.
Приложение Social Services Search Robot готово.
Не получилось?
Если при создании приложения возникли сложности, поищите решение на форуме. Если готового ответа не нашлось, задайте вопрос.
Комментарии (42)
i360u
06.09.2017 04:17+12Только я не понял к чему все эти восторги? Куча специфичных зависимостей, жесткая привязка к спорному тул-чейну без надежды на относительно безболезненную миграцию в будущем, ради чего? БЭМ в CSS — не нужен, потому что есть ShadowDOM как и более легковесные принципы именования, применимые в современной компонентной разработке. БЕМ как шаблонизатор — это жуткий монстр… Половина статьи посвящана получению данных и вообще не связана именно с БЭМ. Что я упускаю, где та "жемчужина" ради которой я отвернусь от своего любимого стека и посмотрю в сторону БЭМ?
ArVaganov
06.09.2017 07:18+1более легковесные принципы именования, применимые в современной компонентной разработке
Можно поподробней, пожалуйста? Тоже использую другой стек (React/Vue + immutable state), но что касается наименования классов в template/jsx кроме БЭМ не встречал более менее адекватных стандартов. Интересно было бы почитать. Что касается самой системы БЭМ, в полном ее понимании, и разумности ее применения – имхо это специфика разработки в большой корпорации, у них там на все заготовленные 'бест-практикс' готовые блоки/модули компоненты в целом и пр. Тем кто хочет идти работать в Y, думаю, точно стоит вчитаться и попробовать сделать проект по этой статье. Недавно была статья как они внедряют новые фичи в свои ресурсы, берут из базы подобный компонент, модифицируют, тестируют делают ревью, добавляют в базу компонентов и потом ставят на прод. Возможно тут с БЭМ действительно получается быстрее.vintage
06.09.2017 10:15+1Мы используем что-то типа облегчённого БЭМ.
Там, где в БЭМ будет:
.my-app__menu > .mol-page__head {}
У нас будет просто:
[my_app_menu_head] {}
То есть каскад вообще не требуется. Генерится такой атрибут автоматом на основе дерева компонент. То есть дом-дерево будет сгенерено примерно такое:
<div my_app mol_book mol_view> <div my_app_menu mol_page mol_view> <div my_app_menu_head mol_page_head mol_view>
Из вот такого вот исходника:
$my_app $mol_book pages / <= Menu $mol_page
Это позволяет задавать стили для компонент (mol_page, например), для их элементов (mol_page_head, например), для элементов компонент, которые сами выступают в роли элементов других компонент (my_app_menu_head, например) и так далее до любого уровня вложенности компонент (my_app_menu_head_close_icon_path, например).
staticlab
06.09.2017 10:23+1У вас не возникает проблем с атрибутами в IE/Edge?
vintage
06.09.2017 11:28Нет, у нас очень мало CSS правил (не больше нескольких сотен) и мало элементов единовременно рендерится (не больше тысячи), чтобы это хоть как-то серьёзно влияло на общее время рендеринга.
Akuma
06.09.2017 17:31А все же, стало интересно. Почему именно атрибуты, а не классы?
vintage
06.09.2017 18:05+1Модификаторы удобно засовывать в значения атрибута:
<div my_button="big accent">
[my_button] { ... } [my_button~="big"] { ... } [my_button~="accent"] { ... }
Хотя, у нас эта возможность пока и не используется. :-)
kashey
07.09.2017 05:54+1Есть HTML driven by CSS — это BEM, где у вас нет проблемы с CSS, но все остальное пляшет под его дудку
Есть CSS driven by CSS — это Tachyons/Turrent и другой atom/functional CSS. Где CSS-а практически нет, зато в html.
<button class="bg-purple f6 br3 ph3 pv2 white hover-bg-light-purple">
И есть CSS-in-JS/ShadowDOM который разными путями немного исправляет генетику CSS+HTML и к нему следует применять немного другие подходы, потому что НЕ нужно именовать что либо по BEM-методолигии так как нет _необходимости_.
>Тем кто хочет идти работать в Y, думаю, точно стоит вчитаться и попробовать
В Яндексе есть много мест где никакого БЕМа нет.vintage
07.09.2017 06:57НЕ нужно именовать что либо по BEM-методолигии так как нет необходимости
Есть. Именование — оно прежде всего для человека. Если человек работает с сотней сущностей, то у всех у них должны быть уникальные имена, иначе он легко запутается.
kashey
07.09.2017 07:34Но функции, классы и переменные вы по БЕМу(и венгерской нотации) не называете?
Декомпозиция и изоляция — вечные друзья и спутники программиста.vintage
07.09.2017 08:03Ещё как называю :-) Благодаря этому как раз и работает автоматическое детектирование зависимостей без портянок import/export.
kashey
07.09.2017 08:07А в bem-react так вообще импорты вычисляемые…
vintage
07.09.2017 08:32Это как?
kashey
07.09.2017 12:15vintage
07.09.2017 12:30Зачем такие сложности?
kashey
07.09.2017 12:34Но это же лучше чем там -> в статье наверху?
vintage
07.09.2017 12:49Чем лучше?
kashey
07.09.2017 12:59Я уже год как не Яндексоид, и мне как-то и то и другое не очень.
babylon
08.09.2017 13:06Кто такие Яндесоиды? Очевидно, что BEM это в корне (или из корня)неверная технология.
Но другой нет. Т.е. есть — JSONNET, но её никто не использует. 21 век. Все по-прежнему делается руками.
Ты же знаешь ответ ;)
Зависит от отдела == опыта команды и требованийЗависит от руководства.
Я бы ваш отдел не моргнув глазом распустил.
Единственное детей и женщин жалко:)
DarthVictor
07.09.2017 11:03Благодаря этому как раз и работает автоматическое детектирование зависимостей без портянок import/export.
Рискну предположить, что заодно и без автокомплита и перехода к определению по Cmd+Click.vintage
07.09.2017 11:12Да нет, всё работает благодаря тайпскрипту.
vintage
06.09.2017 11:13BEMDECL. Определяет список БЭМ-сущностей для страницы.
DEPS. Определяет зависимости между БЭМ-сущностями, которые разнесены по файловой структуре проекта и не отражены в декларации.Зачем отдельная сущность "страница"? Что делать, если мне нужно отобразить одну страницу в качестве блока на другой странице? Почему бы не сделать страницу таким же блоком, как любой другой без своего уникального способа задания зависимостей?
Изучающие БЭМ порой забывают о декларативности технологий и недоумевают: почему для описанного в шаблоне блока, не собираются его стили и скрипты. когда вы описываете шаблон (BEMHTML или BEMTREE) с каким-то блоком внутри (дочерний узел), вы просто добавляете новый HTML-элемент. Чтобы стили и скрипты этого блока попали в сборку, необходимо описать зависимость от него.
Зачем вообще вручную рулить всеми этими зависимостями, если можно подтягивать их автоматически по факту использования? Например, у нас стоит только воспользоваться где-нибудь в своём приложении компонентом $foo_bar, то автоматически будут подключены все стили/скрипты/шаблоны/остальное из директории
/foo/bar
. А если оной не окажется, то она может быть автоматически склонирована с гитхаба, если есть соответствующий маппинг в общем реестре. То есть вот это вот не нужно делать: "Склонируйте bem-express и тд".
i-bem.js Клиентский JavaScript-фреймворк для веб-разработки в рамках БЭМ-методологии.
Почему не TypeScript или хотя бы Flow? Вы же позиционируете фреймворк для больших проектов (с +10 К пользователей в сутки, ага :-)).
Я работал с этим фреймворком на одном из проектов и мне не понравилась работа с модифиакторами посредством триггеров. Это куча ручной работы. Да и сами по себе они весьма ограниченны. Современные фреймворки используют реактивное программирование, которое позволяет задавать инварианты и рантайм уже сам их поддерживает.
moment — JavaScript библиотека для синтаксического анализа, валидации и форматирования дат.
На $jin.time не смотрели?
Чтобы закодировать строку методом Base64
btoa("xvz1evFS4wEEPTGEFPHBog:L8qq9PZyRg6ieKGEKhZolGC0vJWLw8iEJ88DRdyOg")
Приложение Social Services Search Robot готово.
Возможно я плохо смотрел, но я не заметил там работы с базой данных. Вы делаете запрос к апи сервисов на каждый запрос пользователя? Если так, то такой сервис очень быстро заблокируют по лимитам. Какие уж там "+10 К пользователей в сутки".
godfreyd Автор
07.09.2017 11:00но я не заметил там работы с базой данных.
Все верно, работы с базой данных нет, так как не стояло такой задачи. Зачем? Задача показать, какие технологии за что отвечают, и какая из них (BEMTREE) ориентирована на работу с данными. Дальше решает сам разработчик.
+10 К пользователей в сутки
Эта фраза относится к тому, что БЭМ обеспечивает надежную и масштабируемую архитектуру, а не к теме поста.vintage
07.09.2017 11:06Клиент запускается на машине каждого пользователя. Сервер упирается в масштабируемость nodejs+express. Что такого волшебного может дать БЭМ для "+10 К пользователей в сутки"?
asavin
06.09.2017 22:23Представим, что в компании Яндекс планируют на следующей неделе начать разработку нового проекта. Какова вероятность, что этот проект будет использовать i-bem и bemhtml, а не тот же React?
devlev
06.09.2017 23:56-1Интересно, хоть один человек вдохновился этой статьей и перешел на БЭМ? Мне вот почему то интуиция подсказывает что нет. Да и что это за Hello World, в котором мало того что нужно склонировать начальный проект из репозитория, так еще пару файлов подправить чтобы все заработало. И это на минуточку Hello World! Автор статьи даже не удосужился ее опробывать на windows, ибо на виндоус не выполнится команда rm -rf .git. У меня даже собрать проект не получилось потому что инструкция орентирована только на linux пользователей.
godfreyd Автор
07.09.2017 10:39Привет. На Windows мы проверяли, все работало и работает сейчас. Попробовал заново все пройти. Все замечательно. Вы GitBash используете?
Результат:
rm -rf .git
Проект SSSR:
Данные по системе
devlev
07.09.2017 21:20Извеняюсь, теперь и правда все собралось и работает. До этого просто всегда пользовался обычной консолью винды и видимо предупреждение о том что запускать надо только через GitBash осталось в слепой зоне. Спасибо!
godfreyd Автор
07.09.2017 10:52Да и что это за Hello World, в котором мало того что нужно склонировать начальный проект из репозитория, так еще пару файлов подправить чтобы все заработало.
Вы не проект клонируете, а шаблонный репозиторий, на основе которого можно собирать свои динамические проекты.devlev
07.09.2017 21:26Мне просто показалось логичнее шаблонный репозиторий сразу сделать Hello World. Ну или загрузить его как отдельный подпроект готовой сборкой. Скачал, установил, запустил.
vasIvas
Все бы статьи так оформлялись, просто загляденье. Но к сожалению, это не делает вышеописанное понятным. Такое ощущение, что это внутренности монстра из прошлого, а не то что использует аж сам Альфа-Банк.
Удивился, если бы увидел завтра статьи на тему — «прощай angular, здравствуй бэм», " бэм vs react", «создателя redux уличили в подготовки покушения на создателя бэм»… Жуть…
tadatuta
На самом деле всё чуть-чуть иначе: БЭМ в симбиозе с React, мастер-класс по внедрению возможностей БЭМ в проекта на redux и так далее.
А что именно осталось непонятным после прочтения статьи? Мы бы с удовольствием дополнили и/или упростили.
justboris
Я бы назвал это немного иначе: это не БЭМ в симбиозе React, а попытка использовать React при куче легаси кода, написанного на i-bem и других внутренних технологиях.
tadatuta
Борис, «по ссылкам не ходи @ комментарий пиши»?
Там ровно ноль связи с i-bem и каким-либо легаси ;)
justboris
Допустим, легаси в виде кода там нет. Но легаси образ мышления некоторых разработчиков все равно присутствует.
dima117
Ваша логика восхитительна! Поставил вам плюс в карму)
staticlab
Так Альфа-Банк и не использует у себя этого монстра. У нас это "про подчеркивания в классах", но, конечно, не пишем их ручками, а с помощью собственного инструмента. Целую библиотеку компонентов на Реакте так написали.