«Histone» — новый кроссплатформенный шаблонизатор с открытым исходным кодом
Введение
МегаФон — динамичная технологическая компания, работа которой не ограничивается исключительно предоставлением услуг связи. Например, среди наших активов есть большое количество интернет-сайтов, на которых клиенты получают различную информацию и услуги. В рамках проекта по совершенствованию и развитию наших веб-проектов мы, в том числе, создаём продукты, которые могут быть полезны и другим разработчикам. Сегодня мы хотели бы представить первый из них — шаблонизатор Histone, который является opensource-проектом, распространяемым по лицензии Apache Software License 2.0. Но обо всём по порядку.
Что такое Histone?
Многие из вас при создании веб-приложений используют различные шаблонные движки. Ситуация, когда из данных, представленных в определенном формате, вам необходимо сгенерировать некий HTML-код при помощи шаблона, задающего правила преобразования, встречается повсеместно. Несколько лет назад шаблонизаторы активно использовались для генерации HTML-кода на сервере (Smarty, FreeMarker, Velocity), сегодня все чаще и чаще возникает необходимость производить генерацию HTML-кода непосредственно в браузере. В качестве примера таких шаблонизаторов можно привести: TrimPath templates, Mustache, Google Closure Templates и т. д.
При всем разнообразии решений, созданных для работы на разных платформах, шаблонизаторов, которые могли бы быть запущены одновременно и на сервере, и в веб-браузере, существует не так много. У каждого из них есть как свои плюсы, так и существенные минусы. Некоторые из этих минусов, по нашему мнению, являются критичными, что не позволяет в полной мере насладиться всеми преимуществами шаблонного движка, работающего как на сервере, так и в веб-браузере.
Проект «Histone» — это попытка создать новый кроссплатформенный шаблонизатор с открытым исходным кодом в реализациях для языков Java, JavaScript и PHP. Прежде чем приступить к разработке собственного решения, мы изучили преимущества и недостатки уже существующих кроссплатформенных шаблонизаторов. Мы анализировали только популярные шаблонизаторы, широко используемые для построения современных веб-приложений, и не рассматривали решения, у которых нет хотя бы двух из трех интересующих нас реализаций (Java, JavaScript, PHP).
Плюсы | Минусы | |
— Исходный код шаблона компилируется в JavaScript, |
— Для использования шаблона его необходимо предварительно обработать с помощью специальной утилиты. Это существенно усложняет разработку браузерных приложений, поскольку при внесении любого изменения в шаблон он должен быть перекомпилирован. — Слишком сложный синтаксис шаблонов, который будет понятен программистам, но неминуемо вызовет затруднения у дизайнеров шаблонов. — Сложный механизм создания своих расширений. Не позволяет наращивать функционал JavaScript- версии, что делает механизм расширений неприменимым в случае кроссплатформенного использования шаблонов. — Нет PHP-версии |
|
— Существует во всех возможных вариациях для множества языков программирования. | — Нетрадиционный синтаксис, сложный для понимания дизайнерами шаблонов. — В языке шаблонов отсутствует ряд важных конструкций, что делает использование данного шаблонизатора невозможным (по меньшей мере, нетривиальным) в условиях некоторых проектов. — Механизм расширения очень плохо документирован. |
После анализа существующих продуктов наша команда приняла решение о создании нового шаблонизатора, который обладал бы лучшими сторонами вышеперечисленных продуктов, а также исправлял бы те минусы и недочеты, которые являются критичными для нас. В результате был сформирован список основных идей, которые были положены в основу разработки:
- Один шаблон — множество имплементаций шаблонизатора. Синтаксис шаблона не зависит от языка программирования, который используется для его обработки. Это необходимо для того, чтобы одни и те же шаблоны можно было обрабатывать как на сервере, так и в браузере и получать при этом один и тот же результат.
- Традиционный и интуитивно понятный синтаксис. Конструкции, обрабатываемые шаблонизатором, помещаются между разделителями {{ и }}, все остальное попадает в результат обработки шаблона «as is».
- Невозможность выполнения кода напрямую из шаблона. Многие шаблонизаторы могут выполнять код соответствующего языка программирования напрямую из шаблона. Это не позволяет использовать такой шаблон со вставками кода специфического языка в имплементациях на других языках. Поэтому такая возможность в Histone полностью исключена.
- Простота расширения. Вне зависимости от языка программирования, который используется для обработки шаблона, предоставляемый API позволяет добавить новую функцию или свойство для её использования в шаблоне в целях удовлетворения потребностей любого проекта.
- Возможность использования одного источника данных для шаблонов, обрабатываемых на разных платформах. Универсальным форматом данных, для поддержки которого в Histone существует все необходимое, является JSON. Вне зависимости от того, каким набором типов данных обладает язык имплементации, язык шаблона позволяет работать с подмножеством типов данных, определенных для формата JSON.
- Предоставление шаблону данных об окружении, в котором он запущен. Шаблону предоставляется специфическая информация о платформе, на которой происходит его обработка. К примеру, в случае обработки в браузере, шаблону доступна информация о разрешении экрана или размере окна браузера, а в случае обработки на сервере шаблон может получить данные об операционной системе или серверных заголовках запроса.
- Кроссплатформенность и простота портирования. Реализации для языков JavaScript, Java и PHP доступны «из коробки». Отказ от использования специфических внешних библиотек наравне с логичной организацией кода позволяет произвести портирование реализации Histone на любой другой язык программирования, к примеру, C++, Ruby, Objective-C, ActionScript и т. д.
- Производительность. В отличие от Google Closure Templates, Histone не производит преобразование кода шаблона в исходный код того языка программирования, на котором планируется его обработка. Вместо этого существует возможность с помощью специальной утилиты, входящей в состав продукта, скомпилировать исходный код шаблона в форму, исполнение которой будет происходить, минуя этап его разбора и парсинга (самой дорогостоящей операции). Кроме того, на данном этапе происходит выполнение тех частей шаблона, которые не зависят от функций, свойств и переменных, определенных извне.
Архитектура
В составе шаблонизатора можно выделить три взаимосвязанных компонента:
- Лексический анализатор. Производит разбор строки шаблона на токены (последовательности символов исходной строки, объединённые в группы). Создан с использованием встроенного в язык реализации движка регулярных выражений.
- Синтаксический анализатор. Производит синтаксический анализ строки шаблона, результатом которого является абстрактное синтаксическое дерево, отражающее синтаксическую структуру входной последовательности. Создан при помощи алгоритма рекурсивного спуска.
- Интерпретатор. Производит исполнение инструкций абстрактного синтаксического дерева, в ходе которого генерируется результат обработки шаблона. Самая главная часть шаблонизатора, которая производит арифметические операции, вызовы функций, чтение свойств и т. д.
Очевидно, что применение лексического анализатора на основе регулярных выражений и парсера рекурсивного спуска не является самым эффективным подходом к построению подобного рода систем, но это оправдывается тем, что нашей первостепенной задачей являлось обеспечение максимального быстродействия процесса интерпретации шаблона. Поскольку в реальных условиях работа с исходным кодом шаблонов будет происходить лишь в процессе разработки проекта, в то время как веб- приложение в публичном доступе может использовать абстрактные синтаксические деревья шаблонов вместо их исходного кода, тем самым полностью исключая лексический анализ и парсинг.
Синтаксис шаблонов
Шаблон — это текстовый документ со вставками специальных шаблонных тэгов, содержимое которых будет выполнено шаблонизатором в процессе обработки шаблона. Шаблонные тэги — это конструкции языка шаблонов, заключенные между символами {{ и }}. Фрагменты текстового документа вне этих символов будут переданы в результат обработки шаблона без изменений.
Основы синтаксиса
Описание | Пример |
Комментарии | {{* комментарий *}} |
Предотвращение обработки | {{% {{2 * 2}} %}} |
Вывод значений свойств или переменных | {{myValue}} {{myProp.foo.bar}} {{myObject[«foo»].bar}} |
Вызов функций и макросов | {{loadText(«file.txt»)}} {{global.min(10, 20, 30)}} {{myMacro(«foo», «bar»)}} |
Вызов методов | {{«string».toUpperCase()}} {{123.isNumber()}} |
Типы данных
Описание | Пример |
Значение не определено | {{undefined}} |
Значение отсутствует | {{null}} |
Булевы | {{true}} {{false}} |
Числа | {{10}} {{3.14}} {{12E-4}} |
Строки | {{«string»}} {{'string'}} |
Массивы | {{[1, 2, 3]}} {{[«foo»: «bar»]}} |
Операции
Описание | Пример |
Сложение | {{10 + 2}} |
Вычитание | {{10 — 2}} |
Умножение | {{10 * 2}} |
Деление | {{10 / 2}} |
Остаток от деления | {{10 mod 2}} |
Унарный минус | {{-10}} |
Равно | {{10 is 10}} |
Не равно | {{10 isNot 2}} |
Больше | {{10 > 2}} |
Меньше | {{2 < 10}} |
Больше либо равно | {{10 >= 2}} |
Меньше либо равно | {{2 <= 10}} |
Логическое «ИЛИ» | {{true or false}} |
Логическое «И» | {{true and false}} |
Логическое «НЕ» | {{not true}} |
Тернарный оператор | {{true? true: false}} |
Конструкции
Описание | Пример |
Объявление переменной | {{var myVar = 10}} {{var myVar}} … {{/var}} |
Условие | {{if true}} … {{elseif 42}} … {{else}} … {{/if}} |
Цикл | {{for value in values}} … {{/for}} {{for key:value in values}} … {{/for}} |
Макросы | {{macro myMacro(arg1, arg2)}} … {{/macro}} |
Импорт шаблона | {{import «common.tpl»}} |
Вызов функции или макроса | {{call myProc(«arg1», «arg2»)}} arg3 {{/call}} |
Заключение
В данной статье мы постарались коротко описать основные возможности нового кроссплатформенного шаблонизатора с открытым кодом. Вы познакомились с внутренним устройством и основами синтаксиса шаблонов. Если вам интересно подробное описание технологий, на основе которых работает Histone, мы сможем рассказать это в следующем посте, в котором мы рассмотрим, как работает используемый нами лексический анализатор.
Вы можете принять активное участие в развитии проекта и применить его в своих ресурсах. Наша команда с радостью ответит на все возникшие вопросы.