(M)VC Framework Locomotive

в 13:41, , рубрики: node.js

Уже несколько дней я занимаюсь подбором Node.js фреймворка, для решения нескольких демо задач. Прошел я 4 фреймворка (Locomotive, Express, Geddy, Sails) и цикл своих статей я решил начать с Locomotive.

Locomotive в поле моего зрения попал по рекомендации моего товарища, который мне сказал: “Слушай есть интересный новый фреймворк реализующий MVC поверх Express.” — и меня это заинтересовало что в последствии привело к добавлению Locomotive в список “подопытных”.

Архитектура Locomotive и общие концепции

Locomotive представляет себя как: “Строго придерживающийся паттерна MVC и REST принципов, располагающий к написанию хорошо с проектированных приложений“ — но по поводу “MVC” внутри Locomotive мало хочется говорить, оно как бы есть, но, в тоже время, как-то не до конца. Такое утверждение сложилось так как часть «Model» на мой взгляд должна быть реализована хотя бы в каком то виде, но в документации Locomotive автор сослался на статью «polyglot persistence» и сказал что вы мол сами можете выбрать Database & ORM и сами «прикрутить» к фреймворку, такой подход автора немного растроил так как расчет был при выборе этого фреймворка на то что он действительно реализует MVC (Model2) в полном объеме. Вернемся к тому что там таки реализовано.
«View» реализовано за счет Express который в свою очередь интегрирован с такими темплейтерами как Jade, Ejs и многих других.
“Controller” в принципе полноценно реализован, есть базовый класс контролера, можно действительно обработать Request от клиента и вернуть Response. Внутри каждый метод это действие контролера, внутри каждого действия доступно получение параметров роутинга прямо из текущего контекста:

var SearchController = new Controller();

SearchController.find = function() {
  this.query = this.param('query');
  // execute search query...
}

module.exports = SearchController;

Также доступны “помощники действий” позволяющие влезть прямо перед/после выполнением какого то конкретного действия (в Locomotive это называется “Filters”):

PhotosController.before('show', function(next) {
  var self = this;
  if (this.param('id')) {
     next();
  } else {
     return next(“Error”);
  }
});

PhotosController.show = function() {
  this.render();
}

В этом примере мы вставляем “помощника действия” выполняться сразу перед действием “show”, тем самым добавляя слой где мы можем проверить параметр идентификатора и принять решение о продолжении выполнения запроса или его окончании. Также, можно добавить “помощника действий” который будет выполняться перед любым действием в контролере:

PhotosController.before('*', function(next) {
  //код будет выполняться перед любым действием в PhotosController
});

Ну и кроме “помощников действий” в Locomotive есть поддержка механизма “content negotiations”(http://en.wikipedia.org/wiki/Content_negotiation), то-есть внутри действия можно зарегистрировать несколько способов отображения представления в зависимости от формата который запросил клиент, кратко выглядит это так:

PhotosController.index = function() {
  this.respond({
    'xml': { template: 'feed' },
    'html': { template: 'index' }
  });
}

То-есть контролер PhotosController вернет представление в одном из двух форматов в зависимости то того какой формат запросил пользователь в заголовках. При таком значении заголовка Accept действие автоматически вернет зарегистрированный шаблон index:

Accept: text/html;

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

И последнее что я интересного обнаружил в Locomotive это то как они расширили маршрутизацию Express. Они реализовали match() который позволяет создавать маршруты с “placeholder”:

  this.match('songs/:title', { controller: 'songs', action: 'show' });

и добавили на мой взгляд интересный “сахарок”, регистрации не просто маршрутов а целых манипулируемых через REST ресурсов. То-есть вот такая вот строчка:

  this.resources('photos');

Сделает вам доступными такие маршруты как:

Метод: Маршрут: Промапит на action:
GET /photos index
GET /photos/new new
POST /photos create
GET /photos/:id show
GET /photos/:id/edit edit
PUT /photos/:id update
DELETE /photos/:id destroy

И вы сможете описать поведение этих маршрутов контролером PhotosController с соответствующими действиями из колонки “Промапит на action”. Функциональность сама по себе простая но иногда бывает полезной чтобы время с экономить. Вокруг этих всех “фишечек” полно кастомизаций так что не надо думать: “АААААА что делать если мне нужно только show и edit” — об этом разработчик тоже позаботился.

Тестирование простоты в установке и настройке

“Я это сделал, я поставил и настроил Locomotive + Socket.io и сделал все демки которые хотел”, — хотелось бы мне так сказать, но возникла масса проблем. Locomotive устанавливается так же легко как Express:

npm install locomotive -g

а потом создаем проект:

lcm create project

и запускаем:

cd project && lcm server

Все отлично, пока, если открыть браузер на http://localhost:3000 то с вами весело поздоровается Locomotive.
Но моя цель была, настроить так Locomotive чтобы он мог нормально обрабатывать Web Socket запросы и загружать файлы.
С загрузкой файлов проблем нет, так как Locomotive построен поверх Express, и также как это работает в Express так оно и в Locomotive.
Но вот с Web Sockets оказалось немного не приятная ситуация. Почему то разработчик Locomotive посчитал что создание Express (app) обьекта должно быть закрыто как часть фреймворка тем самым обрезав какую либо возможность завернуть Express например в Express.io (конечно можно тупо пропатчить код, но ведь это не наши методы). Тогда я отказался от идеи использовать Express.io хотя она была лучше всего подходящей к Locomotive так как Express.io отлично ложиться на Express поверх которого Locomotive написан. Тогда я решил напрямую подключить Socket.io, но и тут меня ожидало разочарование. Вот например ссылочки по которым люди не могут решить эту проблему без “кастылей”, и разработчик Locomotive не особо торопится «мерджить pull requests» на Github. Да и как то разработка походу вообще не идет над этим фреймворком судя по истории коммитов на Github.

В заключение

В заключение, могу сказать что в принципе, надстройка Locomotive не плохая, но на мой взгляд не расширяемая абсолютно, то-есть делать на ней что то в дальнейшем расширяемое я бы не рискнул, так как пришлось бы много пачить сам фреймворк.
Но если ваши задачи такие как например сделать “Landing Page”, “Визитку”, то для этого Locomotive очень подходит.

Используемая литертура:

http://locomotivejs.org/guide

Автор: Spalax

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js