Маленькая заметка о том, как подружить Heroku, Kraken.js и Sockjs

от автора

Некоторое время назад я, в поисках новых инструментов для реализации очередного «домашнего» проекта, наткнулся на Kraken.js — Open Source проект от PayPal. Kraken.js представляет из себя очередной Node.js-фреймворк, основанный на express. Поискав на Хабре, я не обнаружил, ровным счетом, ничего. Встретил только одно упоминание в виде ссылки на главный сайт здесь.

Чем же он меня привлек, и чем он отличается от известных Derby.js, Meteor.js, Sails.js, и др.?

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

Итак, задача залить Kraken.js-приложение на сервис Heroku, заставить его там работать, и, на сладкое, прикрутить Sockjs.

Оговорюсь, что все описанные далее действия я выполнял на Ubuntu 13.10, но думаю, что для других ОС сильных отличий быть не должно. Для начала идем на heroku.com, регистрируемся и скачиваем Heroku Toolbelt — консольный клиент для работы с Heroku. Вводим в коммандной строке:

$ heroku login 

Теперь мы готовы к разворачиванию приложений на Heroku. Следующим шагом установим Kraken.js, для этого выполняем:

$ sudo npm install -g generator-kraken 

Затем преходим в каталог с проектами и набираем комманду $ yo kraken и в интерактивном режиме отвечаем на вопросы генератора:

      ,'""`.     / _  _ \     |(@)(@)|   Release the Kraken!     )  __  (    /,'))((`.\   (( ((  )) ))    `\ `)(' /'  [?] Application name: Kraken-Sockets [?] Description: A test kraken application with socks.js [?] Author: <Ваше имя> [?] Use RequireJS? (Y/n) n 

Генератор создал каталог одноименный приложению и базовую структуру Kraken.js-приложения. Рассмотрим структуру подробнее:

/config Тут лежат конфигурационные файлы приложения в формате json  /controllers Тут весь роутинг и логика  /lib Сюда можно положить свои и сторонние библиотеки  /locales Файлы локализации  /models Модели  /public Web-ресурсы, статика  /public/templates Тут лежат шаблоны  /tests Функциональные и юнит-тесты  index.js Точка входа в приложение (загрузчик) 

Наберем команду npm start и по адресу localhost:8000 можем полюбоваться работающим Kraken.js-приложением. Хорошо, теперь пришло время залить его на Heroku. Но для начала нужно привести приложение в соответствие с требованиями. Файл package.json у нас уже есть, теперь нам нужно создать файл Procfile с таким содержанием:

web: node index.js 

Этот файл является инструкцией для Heroku, как запускать наше приложение. Кроме этих файлов Heroku требует, чтобы приложение слушало порт, указанный в переменной окружения PORT. Через json-конфиги мы этого сделать не сможем. Специально для этих случаев в Kraken.js предусмотрен механизм программного конфигурирования. Метод отвечающий за программную конфигурацию находится в файле index.js. Мы должны придать ему следующий вид:

app.configure = function configure(nconf, next) {     // Async method run on startup.     nconf.set('port', Number(process.env.PORT || 5000));     next(null); }; 

Ну а теперь создадим git-репозиорий проекта:

$ git init $ git add . $ git commit -m "init" 

И выполним:

$ heroku create kraken-test-socksjs 

Heroku создаст нам приложение, доступное по адресу kraken-test-socksjs.herokuapp.com и сразу подключит нам удаленный репозиторий, push в который устанавливает приложение на сервер.
Пробуем:

$ git push heroku master 

Заходим на kraken-test-socksjs.herokuapp.com и убеждаемся, что все работает. Но не спешим радоваться; самый первый коммит (например добавим что-нибудь в шаблон главной страницы) ломает все приложение. Дальше у меня ушло много часов просмотра логов (комманда $ heroku logs) и гугления. А все оказалось очень просто. Heroku, почему-то, теряет некоторые зависимости второго уровня (зависимости зависимостей приложения — звучит кошмарно, приведу пример: в нашем случае он теряет модуль formidable, от которого зависит модуль kraken-js). И еще он не выполняет grunt-таски по подготовке ресурсов (компиляция less, шаблонов, и т.д.).

Чтобы устранить эти проблеммы делаем следующее: в файле package.json переносим все devDependencies в dependencies и добавляем в dependencies модуль "grunt-cli": "~0.1.13". Это позволит нам вызывать grunt вручную при деплое приложения. После всех изменений файл package.json должен принять такой вид:

{     "name": "kraken-sockets",     "version": "0.1.0",     "description": "",     "author": "Your Name",     "main": "index.js",     "scripts": {         "test": "grunt test",         "start": "node index.js",         "postinstall": "./node_modules/grunt-cli/bin/grunt build --force"     },     "engines": {         "node": ">=0.10.0"     },     "dependencies": {         "kraken-js": "~0.7.0",         "express": "~3.4.4",         "adaro": "~0.1.x",         "nconf": "~0.6.8",         "less": "~1.6.1",         "dustjs-linkedin": "~2.0.3",         "dustjs-helpers": "~1.1.1",         "makara": "~0.3.0",         "mocha": "~1.17.0",         "supertest": "~0.8.2",         "grunt": "~0.4.1",         "grunt-cli": "~0.1.13",         "grunt-contrib-less": "~0.9.0",         "grunt-dustjs": "~1.2.0",         "grunt-contrib-clean": "~0.5.0",         "grunt-contrib-jshint": "~0.6.4",         "grunt-mocha-cli": "~1.5.0",         "grunt-copy-to": "0.0.10"     },     "devDependencies": {      } } 

Обратите внимание на скрипт "postinstall", который как раз готовит ресурсы приложения. С проблеммой ресурсов справились, а что делать с пропавшими модулями? Это видимо баг новой системы кэширования модулей Heroku. Напишу им тикет на днях, а пока я справляюсь с помощью плагина heroku-repo. Просто перед каждым «пушем» релиза я чищу кэш модулей коммандой:

$ heroku repo:purge_cache -a kraken-test-socksjs 

Ух, с дружбой Heroku и Kraken.js справились, теперь самое приятное: прикрутим к Кракену Sockjs.

Sockjs распространяется в виде npm-модуля и отлично прикручивается к express-приложению, но для того, чтобы ее прикрутить нужен доступ к серверу (тот, что представлен модулем http, на который вешается express.js). Так вот в Kraken.js он хорошо спрятан от разработчика. Но, покопавшись в исходниках Кракена, я нашел как его выцепить. Приведу сразу готовый код, который должен быть вставлен в index.js на место этого участка:

kraken.create(app).listen(function (err) {         if (err) {             console.error(err.stack);         }     }); 

Вот он:

var k = kraken.create(app);      k.listen(function (err) {         if (err) {             console.error(err.stack);         } else {             var http = k.app.get('kraken:server');             var sockjs_opts = {sockjs_url: 'http://cdn.sockjs.org/sockjs-0.3.min.js'};             var sockjs_echo = sockjs.createServer(sockjs_opts);             sockjs_echo.on('connection', function(conn) {                 hub.sockjs_pool.push(conn);                 conn.on('data', function(message) {                     hub.sockjs_pool.forEach(function(con) {                         con.write(message);                     });                 });             });             sockjs_echo.installHandlers(http, {prefix:'/echo'});         }     }); 

На этом я закругляюсь. Весь код проекта можно посмотреть на github. Поиграть с развернутым приложением тут.

Очень надеюсь, что эта статься поможет кому-нибудь сэкономить время при отладке Kraken.js-приложений на Heroku и прикручивании к ним всяких вкусностей.
P.S. Это моя первая статья, поэтому конструктивная критика очень приветствуется.

ссылка на оригинал статьи http://habrahabr.ru/post/213199/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *