Фреймворки в Node.js: Djangode
Установка
К сожалению, на данный момент версия в kiwi не устанавливается, поэтому ставим через Git:
git clone git://github.com/simonw/djangode.git
С фреймворком сразу идут примеры, попробуем запустить один:
node example.js
Сервер запускается на 8009 порту (ну почему они все пытаются запуститься где попало?). К счастью, порт легко меняется на 8000 и я получаю доступ через nginx.
Демо-сайт радует страницей с дампом ошибок (да, ошибка в скрипте не убивает Node а показывается в виде аккуратной 500-ой страницы). Также есть демо редиректа и отдачи статического файла. В консоли при этом ведётся лог, правда не слишком подробный.
Также есть пример работы шаблонизатора:
node template_example.js
При запуске выдаётся предупреждение о том что process.mixin скоро будет удалён из ядра Node. При попытке открыть отрендерённый шаблон как HTML всё равно показывает исходник. Видимо заголовок Content-Type не приходит или приходит неправильный. Лезем в исходники — так оно и есть:
['^/text$', function (req, res) {
template_loader.load_and_render('template.html', test_context, function (error, result) {
if (error) {
dj.default_show_500(req, res, error);
} else {
dj.respond(res, result, 'text/plain');
}
});
}],
['^/html$', function (req, res) {
template_loader.load_and_render('template.html', test_context, function (error, result) {
if (error) {
dj.default_show_500(req, res, error);
} else {
dj.respond(res, result, 'text/plain');
}
});
}],
Т.е. это ошибка файла с примером, а не фреймворка. Это уже хорошо. Правим, перезапускаем, видим страницу.
Окей, посмотрим как под этим фреймворком пишется.
Использование
Это пример со страницы проекта:
var dj = require('./djangode');
dj.serve(dj.makeApp([
['^/$', function(req, res) {
dj.respond(res, '<h1>Homepage</h1>');
}],
['^/other$', function(req, res) {
dj.respond(res, '<h1>Other page</h1>');
}],
['^/page/(\\d+)$', function(req, res, page) {
dj.respond(res, '<h1>Page ' + page + '</h1>');
}]
]), 8008); // Serves on port 8008
Первое что бросается в глаза — все пути задаются регулярными выражениями. Пока не знаю насколько это будет влиять на производительность, но думаю для большинства сайтов это вполне подходит. Пути в роутере задаются массивом, как в Nerve. В коллбек передаётся объект запроса — т.е. некоторые вещи с ним видимо всё таки приходится делать самостоятельно. Объект ответа также передаётся, и должен быть передан в dj.respond явно. В этом плане Express мне нравится больше — он абстрагирует нас от внутренних механизмов HTTPServer. Вероятность что нам придётся делать что то с этими объектами на самом деле минимальна.
Окей, что нам доступно ещё? Документация по Djangode к сожалению очень скудная, поэтому будем пользоваться лучшей документацией — исходным кодом
Оказывается, можно всё таки извлекать данные POST-запроса, просто этой функции надо явно передавать объект запроса (req). Шаблонизатор свой, на Mu похожий только синтаксисом, с неплохими возможностями — итераторы, дополнительные функции для обработки строк:
<h1>Ordering notice</h1>
{{ "test" }}
<p>Dear {{person_name}},</p>
<p>Thanks for placing an order from {{ company }}. It's scheduled to
ship on {{ ship_date|date:"F j, Y" }}.</p>
<p>Here are the items you've ordered:</p>
<ul>
{% for item in item_list %}
<li>{{ forloop.revcounter0 }}: {{ item }} {{ forloop.counter|add:"1000" }}</li>
{% endfor %}
</ul>
{% if ordered_warranty or true or false %}
<p>Your warranty information will be included in the packaging.</p>
{% else %}
<p>You didn't order a warranty, so you're on your own when
the products inevitably stop working.</p>
{% endif %}
{{ship.name}}{{ ship.nationality.toUpperCase }}
<p>Sincerely,<br />{{ company }}</p>
Собственно, роутингом и темизацией возможности фреймворка и ограничиваются. В нём нет например работы с cookies или сессией. Возможность отдачи статических файлов — штука неплохая, Djangode даже сам может определять mime-тип отправляемого файла по расширению (поддерживается аж 165 расширений), но по хорошему такую задачу лучше передоверить nginx.
Что на самом деле хорошо — к фреймворку прилагается объёмная библиотека вспомогательных функций для работы с датой, строками и HTML-тегами. Примеры:
var strings = require('utils/string');
var html = require('utils/html');
var text = 'some people, when confronted with a problem, think "I know, I’ll use regular expressions." Now they have two problems.';
html.escape(text); // some people, when confronted with a problem, think &qout;I know, I’ll use regular expressions.&qout; Now they have two problems.
strings.smart_split(text); // Разбивает строку на слова, оставляя фразы в кавычках нетронутыми
strings.add_slashes(text); // some people, when confronted with a problem, think \"I know, I’ll use regular expressions.\" Now they have two problems.
strings.cap_first(text); // Some people, when confronted with a problem, think "I know, I’ll use regular expressions." Now they have two problems.
strings.sprintf('Some people, when confronted with a problem, think "%s" Now they have two problems.', 'I know, I’ll just use regular expressions.');
Все эти функции также можно использовать в шаблонах. Здесь приведена только малая часть функций. В общем, всё то что делает PHP (и видимо Django) таким удобным для простых задач обработки строк, но по умолчанию не входит в JavaScript. Помимо этого есть функции форматирования даты и времени (включая преобразование интервала в строку, например “2 days 4 hours”), различная обработка HTML и даже поддержка reduce для массивов. В функциях обработки дат есть поддержка локалей, позволяющая с небольшими усилиями выводить названия дней недели, месяцев и отрезков времени на нужном языке:
// Internationalization strings
var i18n = {
'en-us': {
days: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
months: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
months_ap: ['Jan.', 'Feb.', 'March', 'April', 'May', 'June', 'July', 'Aug.', 'Sept.', 'Oct.', 'Nov.', 'Dec.'],
ordinal_suffix: { 1: 'st', 2: 'nd', 3: 'rd', 21: 'st', 22: 'nd', 23: 'rd', 31: 'st', 'default': 'th' },
special_times: ['midnight', 'noon'],
timespan: ['year', 'years', 'month', 'months', 'week', 'weeks', 'day', 'days', 'hour', 'hours', 'minute', 'minutes']
}
};
var cur_i18n = i18n['en-us'];
Заключение
По своему интересный фреймворк. В плюсах — неплохая библиотека вспомогательных функций, мощный шаблонизатор, удобная обработка ошибок прямо в браузере; в минусах — отсутствие документации, отсутствие какой-либо поддержки cookies и сессий, которые придётся реализовывать самостоятельно. Вердикт: фреймворк подойдёт для проекта где не нужно работать с сессиями, но надо работать с текстом. Но лучше всё таки взять что нибудь более документированное.
Впрочем, в будущем из этого фреймворка может получиться что нибудь интересное.
Фреймворки в Node.js
- Express
- Djangode
- Nodemachine
- Fab
- Geddy

