Как мы всех на юх послали (ну или продолжение истории про шаблонизотор)

    Вообще я очень любвеобильный человек, особенно в плане различных плюшек. Но что-то во мне переворачивается, как только это вот (еще секунду назад мне искренне симпатичное) обретает ореол святости и становится предметом преклонения. В этот самый момент мой внутренний голос (да я слышу голоса) строго так мне говорит – «пойдем-ка мы отсюда!».

    И такая вот хрень довольно часто происходит в нашем непростом, безумном, но весьма веселом мире технологий. В моем конкретном случае – в мире веб-разработки.

    Позавчера был JQ. Ну полезная ей богу вещица. Но стали появляться специалисты искренне считающие, что JQ – это часть JavaScript и что без оного привязка событий к узлам вовсе невозможна (шепот в зале: потомушта там какие-то проблемы с кроссбраузерностью, цссс). И стали возводиться церкви с храмами, и стал JQ с икон на нас грешных смотреть, и книги писались с названием «Программируем JQuery» (JQ «программируем», Карл!).

    А вчера был AngularJS. И был он великим, потому что стоит за ним… Ага он самый и стоит.

    А сегодня вот ReactJS. Вообще наше все. Почему? Потому что он хороший, потому что он правильный, потому что он против прямого доступа к DOM. А почему? А потому что неправильно к DOM обращаться! А почему? Мальчик, иди в ж#пу!

    Нет, Друзья, не подумайте – у меня вовсе не накипело – поверьте, я брал призовые места на конкурсах лояльности. Просто всему свое место и свое назначение. Палить из танка, пытаясь прихлопнуть муху – это как-то несерьезно. Но в какой-то момент мы начинаем именно это и наблюдать, когда под простенький проект подтягивается пол мегабайта JavaScript (с исходниками на TypeScript, потому что на JS уже никто не пишет и не спрашивайте «почему» — ответ был абзацем выше).

    ReactJS действительно замечательная штукенция. И когда перед нами встала задача сделать приложение с блек джеком и шлю кучей виджетов с возможностью их тягать по рабочему столу (которых должно быть несколько), со всякими окошками, вкладками и прочей фигней, мы без колебаний выбрали ReactJS. Но если к нам приходит «просвещённый» заказчик с простеньким проектом и как бы намекает, что он (проект) должен быть на базе Angualr или ReactJS, то хочется всплакнуть, выпить, подраться и снова выпить в знак примирения. И знаете, почти всегда срабатывает, хотя в отдельных случаях приходится таки выписывать путевку в теплые края.

    Меж тем мне с командой повезло. И как уже отмечалось в предыдущем посте, было мне позволено параллельно развивать простенький шаблонизатор. Хотя что-то мне подсказывает, что у компании на сей счет есть свои собственные сугубо эгоистичные интересы )).

    В общем со времени его первого явления публики, а именно через пять месяцев, шаблонизатор претерпел существенные изменения. О чем и будет данная заметка (гул в зале: все расходимся, это не про ReactJS и даже не об Angular). Стойте! Я еще обязательно несколько раз скажу слово «React».

    Итак, главное, что было сделано – большое объединение параллельных проектов. Теперь одна (немаленькая) библиотека объединяет в себе:

    • Аналог RequireJS
    • Загрузчик ресурсов (вроде CSS файлов)
    • Контролер кэша
    • Всякий базовый функционал (вроде AJAX запросов, инструментов по работе с DOM, CSS и прочее)
    • Ну и шаблонизатор, речь то о нем

    Я ни в коем случае не собираюсь Вас утомлять грудой сухого и скучного материала, а приведу лишь «пару» простых примеров, чтобы показать, о чем собственно речь.

    Вот, например, нужна Вам банальная таблица. И есть у вас API некий, что данные в JSON выдает. Берем и рисуем отдельный HTML файлик с шаблоном. И стили нужные прикрепить не забываем.

    <!DOCTYPE html>
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>Flex.Template</title>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
        <link rel="stylesheet" type="text/css" href="pattern.css" />
    </head>
    <body>
        <table data-type="Demo.Table">
            <tr>
                <th>{{titles.column_0}}</th>
                <th>{{titles.column_1}}</th>
                <th>{{titles.column_2}}</th>
                <th>{{titles.column_3}}</th>
            </tr>
            <tr {{[rows]}}>
                <td>{{column_0}}</td>
                <td>{{column_1}}</td>
                <td>{{column_2}}</td>
                <td>{{column_3}}</td>
            </tr>
        </table>
    </body>
    </html>
    

    Теперь, там, где сие необходимо, рендерим наш шаблон

    _patterns.get({
        //Ссылка на шаблон
        url         : '/components/table.simple/component.html',
        //Указание куда "крепить"
        node        : document.body,
        //Собственно контент
        hooks       : {
            titles  : {
                column_0: 'Column #0',
                column_1: 'Column #1',
                column_2: 'Column #2',
                column_3: 'Column #3',
            },
            //Ссылка на данные для строк таблицы
            rows: _patterns.url('/examples/json/table.json')
        },
    }).render();
    

    Вот собственно и все (тута результат). И что особенно приятно, так это то, что шаблон можно открыть локально и отладить (спокойно, не спеша и не отвлекаясь) стили – ведь перед нами банальная HTML страница.

    Конечно, можно данные и ручками ввести.

    var data_source = [];
    for (var i = 0; i < 100; i += 1) {
        data_source.push({
            column_0: (Math.random() * 1000).toFixed(4),
            column_1: (Math.random() * 1000).toFixed(4),
            column_2: (Math.random() * 1000).toFixed(4),
            column_3: (Math.random() * 1000).toFixed(4),
        });
    }
    _patterns.get({
        url     : '/patterns/table/single/pattern.html',
        node    : document.body,
        hooks   : {
            titles: {
                column_0: 'Column #0',
                column_1: 'Column #1',
                column_2: 'Column #2',
                column_3: 'Column #3',
            },
            rows: data_source
        }
    }).render();
    

    А можно прямо в разметку запихнуть – ничего не возбраняется, ведь главное, чтобы по любви.

    <!DOCTYPE html>
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <!--BEGIN: Patterns definitions-->
        <link rel="pattern" name="my_table" src="/html/table/template.html" data-hooks="rows, c_0, c_1, c_2, c_3" />
        <!--END: Patterns definitions-->
    </head>
    <body>
        <my_table>
            <rows>
                <c_0>0.0</c_0>   <c_1>0.1</c_1>   <c_2>0.2</c_2>   <c_3>0.3</c_3>
                <c_0>1.0</c_0>   <c_1>1.1</c_1>   <c_2>1.2</c_2>   <c_3>1.3</c_3>
                <c_0>2.0</c_0>   <c_1>2.1</c_1>   <c_2>2.2</c_2>   <c_3>2.3</c_3>
                <c_0>3.0</c_0>   <c_1>3.1</c_1>   <c_2>3.2</c_2>   <c_3>3.3</c_3>
                <c_0>4.0</c_0>   <c_1>4.1</c_1>   <c_2>4.2</c_2>   <c_3>4.3</c_3>
            </rows>
        </my_table>
    </body>
    

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

    <div class="tabs-container">
        <div class="tabs-buttons">
            <a class="tab-button">Tab 0</a>
            <a class="tab-button">Tab 1</a>
            <a class="tab-button">Tab 2</a>
        </div>
        <div class="tabs-content">
            <div class="tab-content">
               <p class="tab-content">Tab content 0</p>
            </div>
            <div class="tab-content">
               <p class="tab-content">Tab content 1</p>
            </div>
            <div class="tab-content">
               <p class="tab-content">Tab content 2</p>
            </div>
        </div>
    </div>
    

    Поместив сие в шаблон, то есть в отдельный HTML файл:

    <div class="tabs-container">
        <div class="tabs-buttons">
            <a class="tab-button" {{[buttons]}} onclick="{{@onClick}}">{{button}}</a>
        </div>
        <div class="tabs-content">
            <div class="tab-content" {{[tabs]}}>{{tab}}</div>
        </div>
    </div>
    

    В разметке (на странице) с этим шаблоном cможем делать так:

    <!DOCTYPE html>
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <!--BEGIN: Patterns definitions-->
        <link rel="pattern" name="tabs" src="/html/tabs/template.html" data-hooks="buttons, tabs, button, tab" />
        <!--END: Patterns definitions-->
    </head>
    <body>
        <tabs>
            <buttons>
                <button>Tab 0</button>
                <button>Tab 2</button>
                <button>Tab 3</button>
            </buttons>
            <tabs>
                <tab><p>Content of tab 0</p></tab>
                <tab><p>Content of tab 1</p></tab>
                <tab><p>Content of tab 2</p></tab>
            </tabs>
        </tabs>
    </body>
    

    И читается легче и понятно интуитивно. Вкладки промо-сайта собственно так и сделаны.

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

    Еще можно, понятное дело, создавать свои контролеры под шаблон, наделяя его каким-то функционалом. Можно «на живую» менять значения внутри шаблона (в примере с таблицей – менять значения ячеек); модельки есть, события (непременно стандартные); ну и конечно, допускается получить доступ к DOM и наслаждаться им по мере знаний.

    Много чего там можно делать, о чем почитать не возбраняется вот здесь (исключительно, если есть свободное время).

    Однако отдельно замечу требования, которые выставлялись к Flex-Patterns при его разработке, что от части отражает возможности его использования.

    • первое и самое важное – только стандартный HTML, только текущий стандарт JS. То есть любой шаблон – это просто HTML файл и никаких прибул.

    • это чистое front-end решение, и, хотя шаблоны можно монтировать в разметку, Flex-Pattern является клиентским решением, а не серверным.

    • полная независимость от чего-либо. Достаточно подключить только Flex-Patterns, чтобы начать с ним работу и получить дополнительный базовый функционал (о котором было сказано выше).

    Собственно, это и есть те три кита на которых базируется идея.

    Ну и вновь о React’е (я ж обещал), ибо в прошлый раз было много к нему отсылок и «просьб» сравнить, хотя не сравниваются эти вещи, потому что разные весовые категории. Могу лишь поведать об отличиях.

    • React нуждается в куче обслуживающего персонала дополнительного окружения (для нормальной и комфортной работы). Flex-Patterns полностью самодостаточен (и это не считая возможности создавать модули, наличия базового функционала вроде того, что JQ имеет и иных плюшек) – подцепил и работай.

    • React’у комфортно с npm, а Flex-Patterns даже не знает, что это такое.

    • React использует нечто похоже на HTML, но не HTML. Flex-Patterns основывается только на HTML и не требует знаний о defaultValue.

    • React в целом довольно недоверчив к разработчику и во многом его ограничивает (что, наверное, имеет свои плюсы). Flex-Patterns полностью доверяет тому, кто его приютил подключил к странице.

    • React работает шустрее. Flex-Patterns в целом на 25-35% медленнее, но «заметно» это на небольших шаблонах (скажем на таблице в 1000 строк), где скорость отрисовки у React 100 – 120 ms., а у Flex-Patterns 150 – 200 ms. Если же говорить об огромных объектах (вроде таблицы в 10 000 строк), то результат практически идентичен.

    • Памяти «кушают» оба соизмеримо.

    • React «мешает» разметку и логику, меж тем как Flex-Patterns настойчиво пытается ее разделить и раскидать по файликам (что может показаться неудобным), не допуская никакого кода внутри HTML.

    • React доверяет кэширование браузеру, Flex-Patterns паранойдально кэширует шаблоны самостоятельно.

    • Над React трудится «чуть» больше одного человека, над Flex-Patterns «чуть» меньше.

    • В React есть святое понятие state, а Flex-Patterns атеист и грешить разрешает.

    А напоследок пара слов о будущем проекта (если кому интересно конечно). Проект вырос и его развитие все более и более трудоемкая задача. В ближайших планах – строгая диета, которая по моим оценкам позволит сбросить вес с ~200 кб до 120 – 170 кб (где первое есть голос оптимиста). Также в воздухе витает идея сделать тоже самое, но для JQ, что позволило бы получить на выходе библиотеку размером в 70 – 100 кб (не забывайте внутри не только шаблонизатор, а много еще чего, что по сути дублирует возможности JQ).

    Однако без Вашей поддержки вряд ли обойтись. А! Испугались ))) Нет речь не о финансах. Просто мне выделят чуть больше времени под все это дело, если будут звездочки (я не вру, такое вот условие и выкатили). Для Вас – это клик, а для меня – дополнительная минутка на развитие этого создания. Спасибо заранее.

    Счастья всем, добра и света.

    ЗЫ. Учите React ;)
    Share post

    Similar posts

    Comments 19

      +2

      С Реактом сравнили, ок. А с веб-компонентами? А с Полимером?

        0
        т.е. я правильно понимаю, что в первом примере (который «тута» в буфер никакие данные мышкой скопировать уже нельзя? удобно, чо уж там…
          0
          Спасибо, исправил.
        • UFO just landed and posted this here
          +13
          Но если к нам приходит «просвещённый» заказчик с простеньким проектом и как бы намекает, что он (проект) должен быть на базе Angualr или ReactJS

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

          • UFO just landed and posted this here
              +1
              Я бы не был столь категоричен. Да и нет здесь предмета спора.

              Я особо не идеализирую решения, за которыми стоят (далее список) крупные команды и/или компании. От них сюрпризы случаются совсем нередко. Не стоит их идеализировать. То версию обновят так, что интерфейсы изменятся; то методы отрубят, которые раньше вполне себе работали. В результате для некрупного проекта, версия той или иной библиотеки попросту «замораживается», потому что переделывать все под очередное обновление выходит слишком дорого. В npm можно найти далеко не одно решение для каких-нибудь нужд, например, на базе react. Хорошие решения, грамотные. А запускаешь с последней версией react’a и сыплются в консоль «this method deprecated».

              Поэтому если приходит заказчик и мы видим, что он сам еще толком не знает на какой именно результат ему рассчитывать, до конца не понимает (а порой и не верит) в успех своего проекта – да, мы настоятельно рекомендуем делать проще (не в ущерб бизнес-модели), чтобы как минимум посмотреть, пощупать и понять, как оно там будет. И чаще всего заказчик с нами соглашается.

              Что же до топика, то описанный шаблонизатор как раз и задумывался как максимально упрощенный. Никакого дополнительного синтаксиса кроме стандартного HTML и JS. Как раз для того, чтобы сопровождение и/или мелкая коррекция проекта не вызывала особых трудностей.
              • UFO just landed and posted this here
                  +1
                  Ваш подход абсолютно верен — вы видите конкретного заказчика, вы видите его задачу, вы знаете как ее решать

                  Примером задачи в этой статье является простейшая таблица. Решить ее на React или любом другом фреймворке никак не сложнее:


                  http://jsfiddle.net/zsnjop3h/


                  Кроме того заказчик получает решение, которое может потом поддерживать любой другой разработчик. Фрилансеров с навыками React намного больше, чем желающих разбираться во Flex.Patterns.


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

                    0
                    Извините, Борис

                    Но я никак не могу понять, что вы хотите сказать/доказать?

                    • Что react знает больше людей? Очевидно.
                    • Что я покусился на святое? Я уже ответил Вам ниже, что никто react «уделывать» не собирается.
                    • Что react и подобное нужно использовать везде (даже в до безобразия маленьких проектах)? Весьма и весьма спорный тезис.
                    • Что не нужно / нельзя / запрещено искать собственные решения для тех или иных задач? А как же тогда тот же react на свет появился? До него, что не было альтернатив? А как быть с нашим Яндексом? Уж сколько он «пилит» своих решений. Он тоже плохой?
                    • Или может вы считаете, что если некий проект сделан на react, то его с ходу «прочитает» любой сторонний разработчик? Да, нет. Все также придется какое-то время сидеть и разбираться, что к чему.


                    Конечно, специалистов по react много. Очень много. И эта вот заветная надпись в CV: react или angular, она прибавляет в стоимости специалиста (о чем вы не упомянули). Но… Могу сказать из опыта нашей команды. Мы, как бы это сказать, «побаиваемся» супер-спецов в react / angular / [вписать нужное]. Потому что за тем «комфортом», который создается фреймвоком теряется сам язык и сама платформа. Может, когда-нибудь в будущем pure JS будет чем-то вроде asm сегодня. Но сейчас, мне больно видеть, как «программисты» по JQ теряются и не знают, как сделать ajax вызов без оного. Или супер-спецы по react не понимают, что такое void 0 или элементарные bind, call и apply.

                    Еще раз, у спора должен быть предмет. Я его не вижу. Вы во всем совершенно правы. Но говорите вы не о конкретном решении, приведенном в этой статье, то есть говорите вы не о Flex.Patterns (он же виновник) и даже не о react вы говорите, а говорите вы о том, как в вашей компании ведут бизнес, то есть вы говорите о вашей бизнес-модели. Но статья то не об этом.

                    То, что шаблон на react смотрится не сложнее шаблона на Flex.Patterns – очевидно. Я и не говорил нигде, что он смотрится проще. Я лишь делал акцент, что в Flex.Patterns нет никакого дополнительно синтаксиса, кроме стандартного, что делает его доступным для понимания любому человеку знакомому с JS и HTML.

                    Спасибо.
              0
              А в чем преимущества перед Angular 1.5? По размеру он полегче и вроде большинство перечисленного он умеет. В чем так сказать ваша киллер-фича?
                0
                Почему должна быть киллер-фича?
                  0
                  Ну на самом деле – это верный подход. Должны быть некие свойства/характеристики, которые отличают продукт от его конкурентов/аналогов.

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

                  Сейчас как раз она и есть, стадия разработки. Поэтому я могу дать (и даю) перечень идей, лежащих в основе продукта. Я могу повторить:

                  • Избегание дополнительного окружения (библиотек, тулзов и прочего). Полная самодостаточность и возможность расширения функционала внутри решения со стороны разработчика. Это уже во многом реализовано. Flex.Patterns легко позволяет добавлять свой функционал к тому, что уже есть. Скажем вы «прицепились» к узлу, Flex.Patterns даст вам основной набор инструментов (ну там события прицепить, размеры снять, стили переопределить, анимацию применить и прочее). Но на ряду с этим у вас есть простой интерфейс для добавления своих инструментов к данному функционалу и, что очень важно, интегрировать эти вот свои инструменты внутрь Flex.Patterns – то есть делать свою собственную сборку конечного продукта.
                  • Только стандартный синтаксис. Ну об этом я уже очень много говорил.
                  • Хранение шаблонов и их ресурсов на клиенте.


                  Вот три идеи, которые на данный момент формируют вектор развития проекта. Но, а о «киллер-фитчах» мне пока говорить преждевременно.

                  Спасибо за ваш вопрос.

                    0

                    Насколько я понял из вашей статьи и комментариев, ваша цель – уделать React за счет простоты использования.


                    Вот пример с таблицей, переписанный на React. Никаких дополнительных инструментов, библиотека с CDN и мой код:


                    http://jsfiddle.net/zsnjop3h/


                    И не сказал бы, что получилось сложнее, чем у вас.


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

                      +1
                      У меня, конечно, то еще самомнение, но в одиночку противопоставлять себя замечательным, талантливым и умным ребятам, создавшим react?

                      Нет, я никого не хочу «уделывать». И если вы посмотрите на мой предыдущий пост об этом шаблонизаторе, то увидите, как яростно я отказывался сравнивать шаблонизатор вообще с чем-либо. Во-первых, не время – не все еще готово из задуманного. Во-вторых, и концепция от части может поменяться.

                      Что бы как-то ответить на ваш вопрос, я расскажу (и от части повторюсь) о том, с чего все началось.

                      Какое-то время назад на паре проектов (админки) была необходимость отображать куски (порой большие) HTML. Особенностью было то, что эти элементы (хотя по объему это были порой страницы) нужны были далеко-далеко не всегда. Ну кто ж его знает пользователя, клацнет он по заветной кнопке или нет. Выделять под это дело адрес отдельный (новую страницу) – не выход; а держать в разметке (на тот случай если таки клацнет пользователь) – дорого. Решения были не наши (мы их лишь дорабатывали, а не переделывали, поэтому ни о каких react или чем-то еще и речи быть не могло) и прежняя реализация была через фреймы (тут даже мужчины имеют право на слезу). Тогда возникла идея написать небольшую тулзу (она и была небольшой в самом начале ~2000 строк), которая бы умела грузить HTML файл, проверять его ресурсы (JS, CSS), грузить и их, делать какие-то вставки, все это аккуратно собирать и бережно хранить на клиенте. Вот в этом моменте и был зачат проект. Реализация никаких нареканий не вызвала, все работало (и работает) прекрасно, а версальщик так вообще был очень доволен, ибо получал в работу обычную HTMLшку, которую мог открыть локально и отладить все что нужно. Так вот это все и зародилось. Я же свою идею решил не оставлять, а «повозиться» с ней еще «немного». По мере движения и прикручивания «тулзы» в разные другие проекты она стала обрастать мясом и в итоге вы видите то, что есть сейчас.

                      Иными словами, в момент «зачатия» проекта никто ни о каком react’е не думал и тем более о том, чтобы его уделывать.

                      Что же касается минификации, то этот вопрос все еще открыт. Думаю, над ним. Технически объединение шаблонов не проблема. Но есть ряд иных вопросов, связанных с тем, как вставляет контент в разметку шаблонизатор, что мешает идти, скажем так, простым и накатанным путем.

                      Спасибо за ваш вопрос и ваше время на эксперимент )

                  +1
                  за стиль повествования мне понравилось)
                    0
                    Молодцы, так и надо!

                    Обычно же ещё забывается, что React, Twitter Bootstrap и прочие — это артефакт конкретных компаний, которые во-первых писали их для себя, а значит эти фреймворки являются в том числе решением каких-то их внутренних задач, и по совместительству ещё и общественно полезные и довольно универсальные инструменты. Поэтому там вполне себе много решений, нерелевантных для других конкретных компаний и проектов.

                  Only users with full accounts can post comments. Log in, please.