Вышла третья версия фреймворка Express, в связи с чем прошу обратить внимание на изменения в API. Данная статья является переводом Migrating from 2.x to 3.x.

Удалено

Изменилось

View options

Настройка “view options” больше не нужна, app.locals - это локальные переменные, которые смешиваются с теми, что мы передаём в res.render(), поэтому app.locals.pretty = true эквивалентно res.render(view, { pretty: true }).

Фабрика приложения

express() теперь возвращает функцию, которая выполняет единичный такт приложения Express. Это значит, что можно легко создавать HTTP- и HTTPS-версии приложения, передавая эту функцию в стандартные нодовские методы http.createServer() и https.createServer():

...
var app = express();
http.createServer(app).listen(80);
https.createServer(options, app).listen(443);

Для удобства и простоты метод app.listen() принимает те же аргументы, оборачивая их в HTTP сервер. Следующие примеры эквивалентны:

var app = express();
app.listen(3000);

и

var app = express()
  , http = require('http');

http.createServer(app).listen(3000);

Это означает, что методы, присутствующие в http.Server.prototype, более не присутствуют в app, например, app.address() теперь должен вызываться у экземпляра сервера, который возвращается из app.listen() или того, который вы создадите с помощью http.createServer(app).

Совместимость с Socket.IO

Метод .listen() Socket.IO принимает аргументом экземпляр http.Server. С версии 3.x, express() не возвращает экземпляр http.Server. (См. раздел Фабрика приложения выше.) Чтобы Socket.IO заработал с Express 3.x, создайте вручную и передайте экземпляр http.Server в метод .listen() Socket.IO.

Примечание переводчика. Я, например, передаю в Socket.IO то, что вернуло мне app.listen(), это ведь тоже http.Server

var app = express()
  , http = require('http')
  , server = http.createServer(app)
  , io = require('socket.io').listen(server);

server.listen(3000);

Интеграция шаблонизаторов

Для совместимости с Express 2.x шаблонизатор должен экспортировать следущее:

exports.compile = function(templateString, options) {
  return a Function;
};

Совместимые с Express 3.x шалонизаторы должны экспортировать следующее:

exports.__express = function(filename, options, callback) {
  callback(err, string);
};

Если шаблонизатор не экспортирует этот метод, все равно есть способ - метод app.engine() позволяет сопоставить любую функцию определённому расширению файла. Допустим, есть библиотека markdown, и нужно рендерить .md-файлы, но эта библиотека не поддерживает Express, тогда ваш вызов app.engine() будет выглядеть примерно так:

var markdown = require('some-markdown-library');

app.engine('md', function(path, options, fn){
  fs.readFile(path, 'utf8', function(err, str){
    if (err) return fn(err);
    str = markdown.parse(str).toString();
    fn(null, str);
  });
});

Изменения системы шаблонов

После удаления концепции layouts и partials в Express 3.x шаблонизаторы теперь имеют больше контроля над операциями файлового ввода-вывода. Интеграция с шаблонизаторами теперь существенно упростилась, также упростились внутренние механизмы системы шаблонов.

Это позволяет шаблонизаторам использовать собственные средства наследования, например, последние версии Jade идут с Django-образным наследованием шаблонов (шаблон может указывать от какого шаблона он наследуется). Пример: http://www.devthought.com/code/use-jade-blocks-not-layouts/

После релиза, может быть, появится специальное расширение Express для поддержки partial().

Для поддержки старого функционала с EJS можно воспользоваться express-partials или ejs-locals.

Middleware для обработки ошибок

В версии 2.x метод app.error(callback) был на практике эквивалентен следующему:

app.error = function(fn){
  this.use(function(err, req, res, next){
    fn.apply(this, arguments);
  });
};

Причина в том, что Connect различает “обычное” middleware, и middleware для обработки ошибок через fn.length. У обычного fn.length <= 3, что соответствует (req, res, next), тогда как middleware для обработки ошибок должно иметь ровно 4 - (err, req, res, next).

В 2.x эта функциональность была обёрнута в синтаксический сахар, чтобы упростить API.

Проще гоовря, всё, что нужно для перехвата ошибок, это определить другое middleware, но с четырьмя аргументами. Это middleware должно быть определено ниже всех остальных, чтобы они могли вызывать next(err) для передачи ошибки, как показано ниже:

app.use(express.bodyParser())
app.use(express.cookieParser())
app.use(express.session())
app.use(app.router) // the router itself (app.get(), app.put() etc)
app.use(function(err, req, res, next){
  // if an error occurs Connect will pass it down
  // through these "error-handling" middleware
  // allowing you to respond however you like
  res.send(500, { error: 'Sorry something bad happened!' });
})

Локальные переменные уровня запроса и приложения

.. todo

comments powered by Disqus