Обзор актуальных шаблонизаторов JS. H Пишем простой шаблонизатор на js в черновиках Tutorial Формирование исполняемого кода

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

Не так давно я писал, что вы могли бы попробовать написать свою библиотеку , когда придёт время. Шаблонизаторы же требуют несколько больших навыков и понимания языка, с которым вы работаете, поэтому лучше полагаться на любой шаблонизатор из имеющихся в списке ниже.



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

Если вы разрабатываете на Javascript, то узнаете ряд движков, но можно узнать и о некоторых новых. Я с удовольствием продолжу этот список вместе, и надеюсь, что он вас порадует.

chibi.js

Chibi даёт всё для экономии траффика и времени для отображения шаблона, небольшая и лёгкая библиотека, которая поможет лучше шаблонизировать приложение. Больше фокусируется на CSS вместо использования анимации. (Дословная «вода» автора - перев.)

templayed.js

Это - самый маленький шаблонизатор, с которым вы столкнётесь, гарантированно (Nano - перев.) . Он построен на основе Mustache, прост в использовании и понимании. Сайт имеет большой демо-пример, в котором можно запускать и тестировать код.

ECT

Подобно templayed, ECT тоже имеет демо-страницы установки на сайте, с которыми можно «поиграться» и понаблюдать живые результаты. Он сделан для скорости, и заявляет о себе как о самом быстром шаблонизаторе для JS (построен на Coffeescript). Совместим с Node.js и имеет понятный синтаксис. На Github есть бенчмарки и модульные тесты , показывающие эффективность этой библиотеки.

Pithy.js

Имеется внутренний DSL для генерации HTML в JavaScript. Это отлично для небольших фронтенд-проектов, но не рекомендуется для тяжёлых HTML-страниц.

T.js

T.js использует простую структуру данных Javascript для представления данных HTML / XML.

Nunjucks

Созданный в Mozilla, Nunjucks сделан для нуждающихся в производительности и гибкости из-за возможности расширять пользовательскую библиотеку плагинов и функций.

Jade

Jade рассчитан прежде всего для серверных шаблонов в node.js, но может работать во многих других средах. Он сделан только для XML-подобных документов (HTML, RSS, ...), поэтому не используйте его для оформления простого текста, markdown, CSS и подобных документов.

Dust.js

Dust расширяет Mustache и предлагает высокое качество исполнения по сравнению с другими решениями из этого списка. Содержит очень простой и понятный API.

Движки шаблонизации Javascript Я не пытался приводить примеры, потому что множество ссылок на официальные страницы содержат демонстрации.

Надеюсь, что вы смогли открыть для себя новые варианты для вашего следующего проекта. Уверен, что много альтернатив не упомянуто, но использование перечисленных ощущается больше всего.

UPD : комментаторы статьи-оригинала добавили :

  • "Pure - Simple and ultra-fast templating tool to generate HTML from JSON data
  • Dust.js is used by PayPal, and default in their Kraken.js framework.
  • Swig - A simple, powerful, and extendable JavaScript Template Engine.
UPD2 : упомянуты в комментариях к этой статье :
  • Twig - JS implementation of the Twig Templating Language
  • EJS Embedded JavaScript templates for node

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

  • для совместного использования разметки на страницах;
  • для включения отдельных блоков с функциональностью (при необходимости);
  • в общем и целом для упрощения процесса построения в меру сложных макетов страниц c минимумом прилагаемых усилий.
Сравнение шаблонизаторов

Существует ряд популярных шаблонизаторов для JavaScript, и мы рассмотрим некоторые из них:

EJS

EJS (Встроенный JavaScript) очень напоминает PHP или JSP, очень простые функции – слишком простые для того, чтобы быть хоть в чем-то полезными. Сразу исключаем.

Jade

Наиболее характерной особенностью Jade является то, что он обозначает пробел без кавычек (как Coffeescript),что или является чудом (если вы верите в подобные вещи), или катастрофической неисправностью, если вы реалист (как я). По своим характеристикам этот шаблонизатор стоит на одном уровне с большинством других систем, но его стилевое оформление заставляет нас почти сразу его отбросить.

Mustache / Handlebars

Использует знакомую { { систему токенов } } для встраивания логики в существующие шаблоны (и не только HTML). Обеспечивает хороший набор циклов, логику и управление переменными. Не очень хорошо работает с частичными шаблонами и блоками, а также другими элементами, необходимыми для более легкого создания умеренно сложных структур страниц, что является ключевым требованием даже для самой простой системы CMS, которую я бы хотел видеть. Идем дальше…

Dust

В настоящее время популярен из-за его применения в LinkedIn. На первый взгляд, очень похож на Mustache / Handlebars, но дополнен рядом полезных функций, таких как именованные блоки. Однако процесс загрузки шаблона и рендеринг выглядят довольно неуклюже, и он до сих пор не поддерживает довольно широкий спектр функций для построения страницы. Хорош, но недостаточно…

Nunjucks

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

Итак, у нас есть победитель!

Для справки Основные примеры рендеринга

Давайте рассмотрим некоторые примеры шаблонизатора Nunjucks в действии…

Динамический рендеринг на платформе Node при использовании nunjucks.render

Во-первых, мы рассмотрим пример, в котором будем использовать Nunjucks для рендеринга страницы в ответ на запрос веб-службы, который обрабатывается сервером Node. Этот сценарий очень похож на тот, который происходит при запросе PHP или СoldАusion или страницы ASP .NET на обычном веб-сайте или в веб-приложении.

Предположим, что Node уже установлен.

Устанавливаем Express и Nunjucks:

Npm install express --save npm install nunjucks --save

Создаем нашу базовую структуру app.js:

Var express = require("express") ; var nunjucks = require("nunjucks") ; var app = express();

Настраиваем Nunjucks :

Var PATH_TO_TEMPLATES = "." ; nunjucks.configure(PATH_TO_TEMPLATES, { autoescape: true, express: app } );

Простой путь:

App.get("/home.html", function(req, res) { return res.render("index.html") ; } ); app.listen(3000);

Создаем шаблон index.html:

Привет всем

Запуск с:

Node app.js

и переходим на http://localhost:3000 . Готово!

Добавление динамических данных

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

Для начала давайте передадим некоторые данные функции render:

App.get("/home.html", function(req, res) { var data = { имя: "Энди", фамилия: "Нил" } ; return res.render("index.html", data) ; } );

Во-вторых, мы будем ссылаться на эти данные в нашем шаблоне index.html:

Привет { { data.имя } }

Угадали, что произойдет, когда мы перейдем на http://localhost:3000 ?

Предварительная компиляция при помощи Gulp

Если у вас есть шаблоны, которые не опираются на динамические данные, тогда альтернативой их рендерингу по запросу будет использование инструмента Gulp (или Grunt, если он вам больше по душе) для предварительной компиляции данных во время компоновки.

Предположим, у вас есть простой сайт, состоящий из двух страниц со схожей разметкой:

  • src/index.html
  • src/contact-us.html
  • src/_layout.html

Ваши странички могут выглядеть так:

{ % set title = "Главная" %} { % extends "_layout.html" %} { % block content %} Добро пожаловать { % endblock %} { % set title = "Контакты" %} { % extends "_layout.html" %} { % block content %} Контакты

Звоните нам на 0800 000 0000 или отправьте письмо на эл. адрес [email protected].

{ % endblock %}

{ { title } } { % block content %} { % endblock %}

Устанавливаем плагин gulp-nunjucks:

Npm install gulp-nunjucks --save

Создаем простой gulpfile.js в корневой папке проекта:

Var gulp = require("gulp") ; var nunjucks = require("nunjucks") ; var COMPILE = { SRC: "/src/**.html", DEST: "/dist’ } ; gulp.task("render", function() { return gulp.src(COMPILE.SRC) .pipe(nunjucks()) .pipe(gulp.dest(COMPILE.DEST)) ; } );

Запускаем процесс рендеринга:

Gulp render

Полученные в результате страницы HTML будут выглядеть так:

Главная Добро пожаловать

Разве это не самый лучший сайт в мире?

Контакты Контакты

Позвоните нам на 0800 000 0000 или отправьте письмо на эл. адрес [email protected].

Особенности Nunjucks

Полную документацию можно посмотреть здесь:

В этом разделе мы затронем некоторые из основ для иллюстрации некоторых ключевых функций Nunjucks.

Наследование шаблона

Наследование шаблона - это самый простой путь к многократному использованию шаблонов. При написании шаблона можно определить «блоки», которые дочерние шаблоны могут переопределить. (Это то, что мы делали выше в разделе { % содержание блока %} ).

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

Включения

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

Импортирование и макросы

Импортирование позволяет загружать шаблон и открывать любые переменные и макросы (функции), определенные в нем. Это может быть полезно для таких вещей, как создание функций для последовательного отображения полей формы... немного похоже на написание пользовательских тегов с помощью ColdFusion, например. Для наглядности давайте рассмотрим шаблон под названием forms.html , который выглядит так:

{ % macro field(name, value = "", type = "text") %} { % endmacro %} { % macro label(text) %} { { text } } { % endmacro %}

Мы можем импортировать этот шаблон и использовать его для быстрого рендеринга серии полей формы:

{ % import "forms.html" as forms %} { { forms.label("Username") } } { { forms.field("user") } } { { forms.label("Password") } } { { forms.field("pass", type = "password") } }

Это особенно полезно при использовании таких фреймфорков, как Foundation или Bootstrap , которые требуют разумного количества HTML и CSS сред - если у вас это получилось путем рендеринга в макросе, то код вашего шаблона будет гораздо проще. (Плюс, если ваш шаблон делает весь рендеринг через макросы, то он напрямую не привязан к фреймворку, что облегчает переключение фреймфорков, а также позволяет делать изменения, общие для всех полей формы определенного типа).

Логика – If / For / While

if проверяет состояние и используется для выборочного отображения контента или выполнения других операций:

{ % if variable %} Переменная есть, ура { % endif %} { % if user.authorised %} { % extends "logged-in.html" %} { % else %} { % extends "logged-out.html" %} { % endif %}

for зацикливает массивы:

Var messages = ["Необходимо ввести адрес эл. почты", "Пароль должен быть не короче 8 знаков"];

{ % for message in messages %} { { message } }
{ % endfor %}

Следующие шаги

Советую изучить официальную документацию Nunjucks для более ясного представления о свойствах и возможностях шаблонизатора.
В будущих обзорах я покажу, как можно скомбинировать возможности шаблонизатора Nunjucks с генератором статичных сайтов Wintersmith для построения своей собственной простой и многоязычной системы CMS.

Недавно пришлось столкнуться с уже готовым очень простым проектом, в котором было необходимо добавить вывод дерева категорий и товаров в них. Данные приходили в виде json через запросы к API. В арсенале на фронте был лишь jQuery, а привыкнув к шикарному шаблонизатору Angular’а, я не хотел вновь возвращаться к конкатенации строк, и подключать какой-то фреймворк естественно не имело смысла. Мне необходим был минимальный шаблонизатор, который мог бы повторять куски верстки подобно директивам angular, с условиями и переменными.

Вооружившись статьями авторов John Resig и Krasimir Tsonev , я приступил к работе. В итоге я получил функцию, которая могла компилировать шаблон типа:

min

Начнем с банального:

Var TemplateEngine = function(tpl, data) { // код шаблонизатора } var template = "

Hello, my name is . I\"m years old.

"; console.log(TemplateEngine(template, { name: "John", age: 23 }));

И как вы догадались, хотелось бы, что бы функция возвращала:

Hello, my name is John. I"m 23 years old.

Для обнаружения js переменных в тексте верстки воспользуемся регулярным выражением:

Var re = /]+)?%>/g

С помощью данной регулярки мы сможем находить все что находится между тегами . Параметр /g обозначает, что нас интересует не одно совпадение, а все.

Есть множество способов как использовать в js регулярное выражение, мы воспользуемся методом.exec():

Var re = /]+)?%>/g; var match = re.exec(tpl);

Если мы сделаем console.log переменной match, то получим следующее:

[ "", " name ", index: 21, input: "

Hello, my name is . I\"m years old.

" ]

Как вы видите, наш масcив содержит лишь один элемент, а обработать нам нужно все, поэтому обернем всю логику в цикл while.

Var re = /]+)?%>/g, match; while(match = re.exec(tpl)) { console.log(match); }

Запустив данный код мы найдем обе переменные и .

Теперь самое интересное, нам необходимо заменить найденные переменные их значениями. Самое простое что приходит на ум это сделать простой.replace(). Но это бы работало с простыми json объектами с одним уровнем вложенности. На практике же мы имеем дело с объектами, которые имеют многоуровневую вложенность:

{ name: "John", profile: { age: 23 } }

И tpl.replace(match, data) будет уже не достаточным решением. Потому что когда мы напишем , код заменится на data[«profile.age»] и будет undefined. Так как способ замены нам не подходит, было бы очень круто, если бы между тегами можно было выполнять реальный js код.

Var template = "

Hello, my name is . I\"m years old.

";

Как избавиться от this я расскажу ниже.

Как же это реализовать? В статье Джона Резига он использует new Function для создания функции из строки.

Var fn = new Function("arg", "console.log(arg + 1);"); fn(2); // outputs 3

Для понимания, данный код можно рассмотреть как:

Var fn = function(arg) { console.log(arg + 1); } fn(2); // outputs 3

fn — реальная функция, которая выполняет другую функцию, которая передана как текстовый параметр.

Это именно то, что нам необходимо, нам необходимо шаблон преобразовывать в вид:

Return "

Hello, my name is " + this.name + ". I\"m " + this.profile.age + " years old.

";

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

Return "My skills:" + for(var index in this.skills) { + "" + this.skills + "" + }

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

Var r = ; r.push("My skills:"); for(var index in this.skills) { r.push(""); } return r.join("");

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

Var TemplateEngine = function(tpl, data) { var re = /]+)?%>/g, code = "var r=;\n", cursor = 0, match; var add = function(line) { code += "r.push("" + line.replace(/"/g, "\\"") + "");\n"; } while(match = re.exec(tpl)) { add(tpl.slice(cursor, match.index)); add(match); cursor = match.index + match.length; } add(tpl.substr(cursor, tpl.length - cursor)); code += "return r.join("");"; // /g, reExp = /(^()?(var|if|for|else|switch|case|break|{|}|;))(?:(?=\()|(?=)|$)/g, code = "var r=;\n", cursor = 0, match; var add = function(line, js) { js? (code += line.match(reExp) ? line + "\n" : "r.push(" + line + ");\n") : (code += line != "" ? "r.push("" + line.replace(/"/g, "\\"") + "");\n" : ""); return add; };

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

Var r=; r.push("My skills:"); for(var index in this.skills) { r.push(""); r.push(this.skills); r.push(""); } r.push(""); return r.join("");

И конечно же все это будет успешно скомпилировано.

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

В данном случае mime тип text/html для браузера будет неизвестным и он пропустит выполнение его. Но содержимое этих тегов мы легко можем получить с помощью.innerHTML.

Добавим теперь в начало нашего шаблонизатора проверку, если строка начинается с #, то это id нашего шаблона.

Var html = tpl.charAt(0) === "#" ? document.getElementById(tpl.substring(1)).innerHTML: tpl;

Если строка начинается не с #, значит мы передали сразу шаблон как строку.

И завершающим этапом для нас будет избавление от обращения к this перед каждой переменной, а для этого мы передадим имена переменных scope в параметре new Function, а значения их мы присвоим с помощью метода.apply().

Return new Function(name, code.replace(/[\r\t\n]/g, "")).apply(this,value);

Теперь наш шаблонизатор может принять шаблон типа:

min

при этом js будет выглядеть так:

Var scope = [ { name: "item 1", price: "10$", time: "30" }, { name: "item 1", price: "10$", time: "30" }, { name: "item 1", price: "10$", time: "30" } ]; var template = tpl("#tpl_id",scope);

Теперь содержимое переменной template будет скомпилированной версткой, которую мы можем вставить в любой участок кода.

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

Var tpl = function (str, data) { var name = , value = ; var html = str.charAt(0) === "#" ? document.getElementById(str.substring(1)).innerHTML: str; if (typeof(data) === "object") { for (var k in data) { name.push(k); value.push(data[k]); } } var re = /]+)?%>/g, reExp = /(^()?(var|if|for|else|switch|case|break|{|}|;))(?:(?=\()|(?=)|$)/g, code = "var r=;\n", cursor = 0, match; var add = function(line, js) { js? (code += line.match(reExp) ? line + "\n" : "r.push(" + line + ");\n") : (code += line != "" ? "r.push("" + line.replace(/"/g, "\\"") + "");\n" : ""); return add; }; while(match = re.exec(html)) { add(html.slice(cursor, match.index))(match, true); cursor = match.index + match.length; } add(html.substr(cursor, html.length - cursor)); code += "return r.join("");"; return new Function(name, code.replace(/[\r\t\n]/g, "")).apply(this,value); };

3.2 из 5

Mustache — шаблонизатор, который содержит минимум управляющей логики и доступен для разных языков программирования. Его можно использовать и на сервере (PHP, Ruby и т.д.), и на клиенте (Javascript).

Если вы динамически подгружали с сервера блоки HTML-кода, а не структурированные данные только потому, что не хотели дублировать рендеринг на сервере и на клиенте, то Mustache поможет этого избежать.

Шаблон пишется на простом языке, состоящем из нескольких типов тегов. Теги обрамляются двумя или тремя фигурными скобками с каждой стороны. Можно использовать вложенные шаблоны.

Рассмотрим простой пример шаблона:

{{header}}

{{content}}



    {{#authors}}
  • {{#accent}} {{.}} {{/accent}}

  • {{/authors}}
    {{^authors}}
  • anonymous

  • {{/authors}}

Данные, с которыми работает шаблон, называются контекстом. Имя тега указывает, к какому полю контекста необходимо обратиться. Пример данных, которые могут послужить контекстом для нашего шаблона:

Var data = {
header: "Новый пост",
content: "Первая строка
Вторая",
authors: ["alex", "daemon", "john"],
accent: function () {
return function (text, render) {
text = render(text);
return "" + text + "";
}
}
};

Чтобы «запустить» шаблонизатор и отрисовать с помощью шаблона данные, необходимо подключить библиотеку:

И вызывать рендеринг методом to_html:

Mustache.to_html(template, data);

Здесь первым параметром передается шаблон, а вторым — данные. Так же можно использовать третий параметр —список дополнительных шаблонов, и четвертый — функцию callback, которая вызывается после обработки шаблона.

Более подробно о тегах

Всего в Mustache четыре основных типа тегов: переменная , секция , комментарий и подключение дополнительного шаблона .

Переменная выводит данные с экранированием HTML-сущностей {{header}} и без экранирования {{{content}}} . Отличаются они количеством скобок. В нашем случае, вместо {{header}} подставится строчка «Новый пост».

Секция представляет собой парный тег. Принцип ее действия зависит от типа данных, с которыми она работает. Если в контексте имени секции соответствует поле со списком, то шаблонизатор проходит по его элементам и текст внутри парного тега обрабатывается по одному разу для каждого элемента списка. Элемент списка подставляется заместо тега-точки. Так, например, секция {{#authors}}

  • {{.}}
  • {{/authors}} превратится в
  • alex
  • daemon
  • john
  • . Если список пуст, то обрабатывается содержимое «тега с крышечкой», в нашем случае — это {{^authors}} … {{/authors}} .

    Если имени секции соответствует функция, то для подстановки будет использован результат ее выполнения.

    Если поле, соответствующее имени секции, не является ни списком, ни функцией, то оно будет использоваться в качестве контекста для обработки содержимого тега.

    Комментарий оформляется в виде тега с восклицательным знаком, например, {{! comment content}} .

    Подключение дополнительного шаблона вызывается с помощью тега с угловой скобкой. Например, {{>copyright}} . Если в текущем контексте присутствует поле с таким названием, то оно будет передано в качестве контекста для подключаемого шаблона.

    Производительность

    Вопросы производительности Javascript шаблонизаторов рассматриваются в этой статье . Автор провел тестирование восьми шаблонизаторов и выяснил, что на простых шаблонах Mustache показывается лучшую производительность.

    Но так как я частенько увлекаюсь JavaScript"ом, то решено было найти подобный шаблонизатор для этого языка, но серверного (node.js, ага). Первые ссылки в поисковике выдают такие шаблонизаторы, как: ECT , JUST , . Все они, естественно, не подходили для меня, т.к. слишком далеко были от синтаксиса Smarty.

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

    Итак, свои корни проект пустил примерно 4 месяца назад, в сентябре 2012 года и постепенно обретал рабочий вид. По началу весь алгоритм компиляции шаблонов брался из Smarty (файл Smarty_Compiler.class.php), некоторые функции не были перенесены. В процессе написания кода я делал всевозможные сокращения кода в плане простоты, так как это «мой стиль». Поэтому были заменены все огромные регулярные выражения (да и в них, кстати, всё равно было полно ненужного мусора), часть логики в функциях.

    Так как проект необкатанный, то совершенно понятно, что в процессе будет найдено достаточное количество багов. Также уверен, что будут жалобы в сторону обработок ошибок в шаблонах (на данном этапе эта «функция» реализована плохо). Я буду только рад получать сообщения об улучшении кода, и по мере своих возможностей вносить как исправления, так и новые функции.

    Примеры работы шаблонизатора:

    compiler.js:
    var NodeSmarty = require("./NodeSmarty/"); var Template = new NodeSmarty(); Template .setTemplateDir("./templates/") .setCompileDir("./compile/") .setCacheDir("./cache/"); var Array = ["val1", "two"]; Template.assign({ "Value":"first", "number":10, "array":Array }); var Final = Template.fetch("template.tpl", function(data) { console.log(data); });

    template.tpl:
    {include file="header.tpl.html"} {$Value} {$number*10/20} {if !$Value} //... {elseif $number = $Value} //... {else} //... {/if} {* comment *} {literal} for(var di=0; di < 10; di++) { console.log(di); } {/literal} {foreach from=$array item=Foo key=Key} Item: {$Foo} key: {$Key} {/foreach}

    Скорость выполнения кода выше, чем у EJS и JUST. Происходит это из-за того, что при повторном запросе файла, вызывается не шаблон, а уже скомпилированный код. Но есть и еще один плюс (хотя его и нет, но будет в будущем) - повышение скорости выполнения также зависит от файловой системы (дада, сначала нужно проверить, не изменились ли шаблоны, перекомпилировать их). Если же компилировать файлы при первом запросе, а при последующих просто выгружать из памяти, то скорость соответственно увеличится, и время выполнения кода станет еще меньше!

    Сравнение скорости выполнения кода при 1000 итераций:

    Немножко о принципе работы.

    Если шаблон изменен раньше, чем скомпилирован файл, то библиотека просто подгружает скомпилированный файл и подставляет в него значения. Если же шаблон изменен позже, то выполяются следующие инструкции:

    Первым делом парсится документ на наличие открывающего тега: { и закрывающего тега: } (хотя можно и изменить по желанию, см документацию).
    Потом каждый тег парсится на главный параметр и атрибуты. Главный параметр также проходит обработку и разбивается на 2 типа: команда или переменная. Переменная отличается от команды впередистоящим знаком доллара ($ ). И переменная и команда проходят обработку для преобразования себя в рабочий JavaScript код. Скомпилированный код записывается в файл и происходит eval текста (хотя там не eval, а new Function() ).

    mob_info