Skip to content

Latest commit

 

History

History
446 lines (325 loc) · 23.2 KB

article.md

File metadata and controls

446 lines (325 loc) · 23.2 KB

Привет, я Вадим, это мой друг Марат. Мы из Яндекса. Из Карт. Спасибо, что пригласили :)

Мы любим строить сайты. И нам хочется получать от этого удовольствие. Теперь мы получаем радость, потому что придумали Бивис.

У меня есть ребенок. Восемь лет девочке. У кого из вас есть ребенок и он чуть-чуть умеет на html/css и javascript? Принесите ему сегодня ссылку на документацию к БИВИС, и завтра он принесёт вам полноценный сайт, работающий на Node.js

Амбициозно, но заманчиво? Но вы-то не школьники. А кто вы?

Если вы:

  1. Разработчик из команды, в которой больше 4-5 человек

  2. Разработчик сервиса (сервисов), в котором много похожих блоков или страниц

  3. Разработчик общей библитеки блоков

тогда Бивис для вас тоже.

Должны сразу признаться. У нас нет цели заполучить вас в контрибьютеры или принести вам новую веб-религию. Мы не претендуем на мировые лавры. Мы просто с вами по-братски делимся своими придумками.

Ну всё, хватит общих слов, давайте к станку!

##Какие способы разработки сайтов мы знаем?

  1. Статический сайт - нагенерить html-страничек, сложить их сервере под управлением Апача, к примеру. Ну и всё.

    [смотрим на схему Apache/статический html]

  2. Динамический сайт. На том же сервере под управлением Apache работает, к примеру PHP-шаблонизатор. Мы пишем уже не html-странички, а php-странички. В php-файлы мы описываем, как обращаемся в MySQL-базу за данными, а потом там же в php-файле эти данные из базы принимаем и на их основе генерим html-код страницы. А потом Апач отсылает html назад в браузер.

    [смотрим на схему Apache/php-шаблонизатор]

    Всем известная схема. Ну, разве что, моя дочка про неё ещё не слышала, ей восемь лет, я не торополюсь её знакомить с миром веб-разработки :)

  3. Вот эта же схема, кому-то именно она ближе:

    [смотрим на схему Lighttpd/xml+xsl/XSLT]

    Всё то же самое, только на других технологиях. А у вас это может быть на Python + Django. Ну или Ruby и какие-то серванты.

Ну так мы эту схему и не меняли. Мы заменили в ней составляющие.

[смотрим на схему Node.js/btjson+bt.js/BT]

Вместо Apache у нас Node.js. Вместо php-страничек мы пишем js-файлы, в которых мы обращаемся в серванты за данными, и на основе полученных данных создаём конечный html. Разница лишь в том, что вместо PHP/XSLT-шаблонизаторов мы используем Javascript-шаблонизатор BT, который написали сами.

Возникает вопрос: зачем нужен новый шаблонизатор, если всё уже есть?


Школьнику, который знает чуть-чуть html/css и немного javascript-а, не нужно учить серверный язык программирования - ни PHP, ни Ruby, ни Python. Что ещё учить не надо - Perl, Java, C#, XSL, продолжайте. Я понимаю, что у каждого языка свои преимущества в определённых ситуациях. Но мы и не говорим, что они не нужны. Мы говорим, что типовые задачи веб-разработки можно успешно делать на серверном javascript, который мы уже знаем.

Вот и мы захотели обрести полный контроль над фронтендом. Самое время! Есть все возможности!


Итак, запрос от пользователя пришёл на сервер. На сервере крутится Node.js приложение, которое приняло запрос, заглянуло в маршрутизатор и поняло — нужно взять index.btjson.js и сгенерить из него html.

Что такое BTJson? Это способ описывать страницы. В статических сайтах страница описыватеся чистым html, в php-сайтах - php-командами, в сайтах на XSLT - описываеся в виде xml, а у нас в виде json. Вот так:

[
    {
        block: 'head'
    },
    {
        block: 'authorization',
        actionUrl: '/?task=login'
    }
]

В какой-то такой html он превращается на лету:

<div class="head">
    ...
</div>

<form class="authorization" action="/?task=login">
    ...
</form>

Там где три точки, там весь остальной html, нужный для устройства шапки или формы логина.

Мы больше не пишем html-теги, потому что в Яндексе мы давно научились смотреть на веб-страницу, как на набор блоков. Каждый выполняет свою простую функцию, вместе - это страница.

Вы, скорее всего, тоже разбиваете страницу на небольшие части, и называете их про себя как-то: кто модулями, кто ещё как. Мы называем блоками, потому что мы из Яндекса, а там родилась концепция верстки, в которой впервые прозвучало слово "блок". :)

Вы помните такую концепцию?

2006 год. Родилась концепция АНБ. Это были рекомендации по оформлению кода в проекте.

2009-210 года. Родился БЭМ. Фреймворк для разработки сайтов. Это реализация АНБ, которую насытили дополнительными идеями, которых не было ещё в 2006 году.

2013 год. Мы придумали Бивис. Это тоже фреймворк для разработки сайтов. Фактически, это не что иное, как альтернативная реализация АНБ, сделанная после БЭМа. Мы не согласны с реализацией АНБ командой БЕМ-разработчиков, и реализовали фреймфорк, который, как нам кажется, реализует первоначальные принципы АНБ — настоящую абсолютную независимость блоков.

Что такое блок?

Это некая логическая единица веб-страницы. Абстрактная штука. Давайте будем считать, что набор тегов, которые формируют структуру формы авторизации, это и есть некий блок. Назовём его authorization. Внутри него есть некие теги, без которых форма не сможет выполнять свою функцию - принимать данные от пользователя и откправлять их на сервер - текстовый инпут и сабмит-кнопка. Эти теги бессмысленны без формы, поэтому их можно считать элементами блока. Такая вот абстракция.

А вокруг этой абcтракции придумали немного правил для облегчения разработки.

  • Для стилизации блоков не используем id, а только css-классы.
  • Чтобы исключить наложение стилей элементов от разных блоков, вложенных друг в друга, классы для элементов обязательно включают в себя имя блока
    <div class="page">
        <h1 class="page__title"></h1>
    
        <div class="article">
            <h2 class="article__title"></h2>
        </div>
    </div>
    
  • Чтобы в html/css сэмулировать наследование и полиморфизм, придуманы модификаторы. Например, на странице две кнопки, но одна синяя, другая зеленая. Пишем стили для синей кнопки, а для того, чтобы сделать вторую зеленую, используем синюю, но модифицируем дополнительным классом, в котором только одно css-свойство:
     <style>
         .button {
             /* все стили для синей кнопки */
         }
    
         .button_green {
             background: green;
         }
     </style>
    
    <div class="button">синяя кнопка</div>
    <div class="button button_green">зеленая</div>

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

Описание страницы обязано быть простым

Это важно. Описание страницы должно быть масикмально простым. Чем предмет проще, тем легче им пользоваться. Бабушка моей жены любит печь хлеб сама. Мы подарили ей хлебопечку. Казалось бы - насыпь муки, дрожжей, налей воды и масла и нажми пару кнопок - очень просто. Но бабушка Дуся не пользуется, потому что не может запомнить в какой последовательности какие кнопки нажимать - из инструкции старому человеку это непонятно. Пользуется газовой духовкой - куда проще - поджечь комфорку, сунуть противень внутрь, закрыть дверцу.

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

Вот такие описания блоков.

[
    {
        block: 'head'
    },
    {
        block: 'authorization',
        actionUrl: '/?task=login'
    }
]

Смотрите, здесь не описано ни одного элемента, ни одного тега и атрибута. Но из каждой декларации сгенерится развесистый html, например это может быть такой:

<div class="head">
    <a class="head__logo" href="/"><img src="logo.png" /></a>

    <h1 class="head__title">Демо-страница</h1>

    <a class="head__rss" href="/?rss"><img src="rss.png" /></a>
</div>

<form class="authorization" action="/?task=login">
    <input class="authorization__login" value=""/>
    <button class="authorization__submit"/>
</form>

Или даже больше. Но я не хочу думать про такой html. Я хочу мыслить простыми предметами - блоками. А что о блоке мне нужно знать, чтобы позвать его на страницу? Да только имя. И это так по человечески. Ведь, когда я хочу позвать к себе в гости Марата, я делаю этоочень просто - я зову его по имени и говорю: "Марат, а приходи к нам в гости сегодня, жена яблочный пирог испечёт, посидим". А у Марата жена и двое детей, к примеру. Я же не зову его отдельно, отдельно его жену и каждого ребенка в отдельности. Нет, только его, а уж он сам приведеёт всё семейсвто, будьте уверены.

    {
        друг: 'Марат'
    }

И с блоком так же. Я НЕ ХОЧУ думать, о том, как он внутри устроен, из каких элементов. Я зову его просто по имени. Ну и если надо сообщаю блоку какую-то дополнительную информацию. Командир в окопе кричит солдату: "Рядовой Петренко, прикрыть правый фланг!".

{
    рядовой: 'Петренко',
    стрелять: '/?туда'
}

Всё! Командир приказал — Петренко стреляет, куда сказали. И пусть Петренко сам решает какой рукой стрелять - левой или правой, каким пальцем на спусковой крючок жать - указательным или ещё каким. Командиру какое дело до этих деталй вообще?

Ну что, похоже на правду?

[
    {
        block: 'head'
    },
    {
        block: 'authorization',
        actionUrl: '/?task=login'
    }
]

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

Внутренности блока

Ну, в самом деле, я когда в ресторан прихожу, и заказываю солянку, я же не даю указаний официанту: "Так, дорогуша, нагрей суп в каструле, потом налей два половника в глубокую тарелку, насыпь сверху зелени и сметаны ложку и только после этого неси мне." Нет, я просто говорю: "Мне солянку". Я точно знаю, что в кафе солянка уже сварена, её сейчас мне подадут.

И с шапкой так же: "Мне шапку!"

{
    block: 'head'
}

Если блок уже разработан кем-то по правилам Бивиса, например в какой-то общей библиотеке, вам хорошо — позвали блок и voila — сегенерировался нужный html блока.

Но это когда вы пользуетесь готовой библиотекой блоков и в рестораны обедать ходите.

Другое дело, когда я дома говорю жене: "Хочу на ужин борщ с фасолью и сметаной". Знаете, что мне жена отвечает? "Легко! Картошку чисть..."

Улавливаете? Если вы создаёте новый блок, вам придётся предватительно самому и картошку начистить и фасоль вымочить, и мясо кубиками нарезать. То есть сварить борщ по некоторым правилам. И только потом вы сможете щелкнуть пальцами и борщ окажется у вас в тарелке.

Чтобы btjson превратился/трансформировался в html, вам нужно написать правила для трансформации. На XSLT писали? XML в HTML трансформировали? Та же идея: пишем шаблоны. Всё, как в XSL.

А есть кто не писал на XSL? Вы тоже сейчас поймёте.

Когда браузер запрашивает index.html, Node.js сервер обрабатывает ваш запрос и находит ваш btjson

{
    block: 'head'
}

И передаёт управление специальному шаблонизатору, который называется BT. Всё как с PHP, схема та же. У BT одна простая задача — превратить btjson в html.

[смотрим на схему Node.js/btjson+bt.js/BT]

BT - это и есть повар в ресторане или ваша жена на кухне. Именно BT готовит внутренности блока, то есть формирует нужный html.

bt.match('head', function (ctx) {

    ctx.setTag('div');

});

Ваше описание блока приходит в функцию bt.match в виде переменной ctx. Эта функция физически находится в файле index.bt.js.

[смотрим на схему Node.js/btjson+bt.js/BT]

Конкретно этот шаблон сегенерит простой html

<div class="head"></div>

BT — это очень простой декларативный шаблонизатор. Он берет json и "накладывает" на него правила. Это как пазлы - совпали предмет и отверстие - опа - картинка сложилась. Это как XSLT. Это как в CSS.

h1 {
    color: red;
}

Что это? Даже школьник ответит: "Это CSS-селектор". Ну тогда поздравляем, вы умеете писать декларативные шаблоны.

CSS-селекторы - это декларативные шаблоны. Заголовок станет красным только, если он есть на странице. Если h1 на странице нет, то и красить нечего, правда?

В этом вся соль декларативных языков программирования. Вместо явных инструкций (как в PHP) - только матчеры, которые применяются к данным, если они есть. Матчатся или не матчатся.

Вот шаблон на BT.

bt.match('head', function (ctx) {

    ctx.setTag('div');

});

Он записывается в виде функции match, в которую мы передаём имя блока. Очень похоже на CSS. А вторым аргументом пишем функцию, внутрь которой передаём исходный btjson в переменной ctx

Давайте усложним. Я хочу, чтобы внутри шапки появился заголовок.

Я добавил комментарии в код, чтобы вы всё поняли, а я помолчу.

// регистрируем матчер для блока head
bt.match('head', function (ctx) {

    // устанавливаем HTML тег для самой шапки
    ctx.setTag('div');

    // Генерим внутри шапки новый btjson и устанавливаем его, как содержимое шапки
    ctx.setContent({
        elem: 'title', // указываем элемент title в качестве содержимого
        text: 'CodeFest 2014' // произвольный текст для заголовка
    });

});

// регистрируем матчер для элемента title блока head
// внутри ctx уже json, переданный в родительском ctx.setContent()
bt.match('head__title', function (ctx) {

    // выставляем тег h1 для элемента title
    ctx.setTag('h1');

    // Получаем параметр text
    var text = ctx.getParam('text');

    // задаём содержимое заголовку
    ctx.setContent(text);

});

Результат:

<div class="head">
    <h1 class="head__title">CodeFest 2014</h1>
</div>

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

// регистрируем матчер для блока head
bt.match('head', function (ctx) {

    ctx.setTag('div');

    ctx.setContent({
        elem: 'title',
        text: ctx.getParam('text') // получаем значение из параметра
    });

});


bt.match('head__title', function (ctx) {

    ctx.setTag('h1');

    var text = ctx.getParam('text');

    ctx.setContent(text);

});

И тогда в btjson можно передать опцию/параметр

{
    block: 'head',
    text: 'CodeFest 2014, Новосибирск'
}

Наш результат:

<div class="head">
    <h1 class="head__title">CodeFest 2014, Новосибирск</h1>
</div>

А вот посмотрите на реальный пример их Яндекса. Это btjson-описание шапки.

{
    "block": "y-header",
    "view": "islet-search",

    "showSearch": true,
    "searchAction": "/",
    "searchQuery": "Текст запроса",

    "showUser": true,

    "userPic": "user.jpg",
    "userLogin": "FenekFox"
}