Ровно три месяца назад я представил хабрасообществу JavaScript шаблонизатор ECT. Вчера для него вышло обновление, о котором я хочу рассказать в этой статье.
Вы знакомы с ECT?
ECT это JavaScript шаблонизатор со встроенным CoffeeScript синтаксисом (отсюда и название: Embedded CoffeeScript Templates). ECT изначально разрабатывался с упором на максимальную производительность и при этом он предоставляет разработчику богатый набор функций.
Что нового?
Производительность
Теперь ECT можно назвать самым быстрым JavaScript шаблонизатором. По данному пункту на ближайшее время работа завершена, т.к. достигнута скорость, к которой стремился изначально.
Предварительная компиляция шаблонов на сервере, перед отдачей на клиент
После публикации ECT, я получил много различных отзывов, как с критикой, так и с благодарностью. Были отзывы и с предложениями. Одним из самых частых предложений было добавить возможность предварительной компиляции шаблонов на стороне сервера, чтобы не загружать на клиент довольно тяжёлый coffee-script.js и улучшить клиентскую производительность.
Теперь такая возможность появилась. Компилятор реализован в виде middleware для connect/express.
Работает это так:
- Настраиваем шаблонизатор на сервере;
- Добавляем middleware компилятора шаблонов в стек нашего connect/express приложения;
- На клиенте в качестве root указываем url, который будет обслуживать middleware.
Когда клиент запрашивает шаблон с сервера, этот запрос обслуживает middleware компилятора шаблонов, и в ответ клиент получает уже скомпилированный шаблон. В связи с этим, отпадает необходимость подключать CoffeeScript компилятор на стороне клиента и при этом, нам не придётся компилировать шаблоны вручную после каждого изменения. Компилятор всё сделает сам.
Однако, ручная компиляция всё же может пригодиться. Например, для использования шаблонизатора без Node.JS в качестве сервера или с PhoneGap (с которым ECT отлично дружит). В TODO уже занесен пункт создания утилиты предварительной компиляции шаблонов из командной строки.
Пример использования middleware:
var connect = require('connect');
var ECT = require('ect');
var renderer = ECT({ root : __dirname + '/views', ext : '.ect' }); // Настраиваем шаблонизатор. Здесь параметр root это путь к директории с шаблонами на диске.
var app = connect()
/**
* Подключаем middleware компилятора шаблонов.
* Тут параметр root обозначает base url, который будет обслуживать шаблонизатор.
* Т.е. по url http://server:3000/views/page будет доступен скомпилированный шаблон из __dirname + '/views' + 'page.ect'
*/
.use(renderer.compiler({ root: '/views', gzip: true }))
// Тут могут быть остальные middleware
.use(function(err, req, res, next) {
res.end(err.message);
});
app.listen(3000);
В конфигурации шаблонизатора на клиенте мы дожены указать тот же root, что и в конфигурации middleware компилятора шаблонов.
var renderer = ECT({ root : '/views', ext : '.ect' });
var data = { title : 'Hello, World!' };
var html = renderer.render('template', data);
Полная поддержка фреймворка express
Подключить ECT в качестве шаблонизатора в express теперь не составляет проблем.
var express = require('express');
var app = express();
var ECT = require('ect');
var ectRenderer = ECT({ watch: true, root: __dirname + '/views' });
app.engine('.ect', ectRenderer.render);
app.get('/', function(req, res){
res.render('index.ect');
});
app.listen(3000);
console.log('Listening on port 3000');
Синтаксис
Добавлена возможность синхронного вызова метода render.
Это немного увеличивает производительность, когда ошибки отлавливаются централизованно, например при помощи connect-domain и даёт свободу выбора стиля написания кода.
Асинхронный стиль:
var renderer = ECT({ root : '/views' });
var data = { title : 'Hello, World!' };
renderer.render('template.ect', data, function (err, html) {
});
Синхронный стиль:
var renderer = ECT({ root : '/views' });
var data = { title : 'Hello, World!' };
var html = renderer.render('template.ect', data);
Стоит отметить, что оба варианта выполняются синхронно. Разница только в стиле написания и в том, что первый вариант передаёт ошибку в callback, а второй, в случае ошибки, делает throw. Второй вариант работает немного быстрее.
Добавлена поддержка многострочных выражений.
Хотя мне самому не очень нравится идея написания хелперов внутри шаблонов, об этой возможности спрашивали достаточно часто (в issues шаблонизатора eco также просили добавить эту возможность), поэтому решено было её реализовать.
Теперь в коде шаблонов можно определять небольшие функции или выполнять другой код.
Пример:
<%
truncateHelper = (str) ->
if str.length > 10
return (str.substr 0, 10) + '…'
else
return str
%>
<div>
<%- truncateHelper @title %>
</div>
Автор: BVadim