
Зачем еще одна платформа
Как уже знают многие читатели, я старательно и планомерно продвигаю на Хабре нашу платформу облачной телефонии voximplant, которая полностью управляема с помощью javascript и дружественна к веб разработчикам. К нам часто обращаются клиенты и партнеры, которые хотят из javascript во время звонков сохранять и читать данные: собирать статистику, рисовать dashboard, делать синхронизацию по внешним событиям и так далее. Мы им честно рассказываем что из нашего облака можно делать http запросы к любым сервисам, с помощью которых можно реализовать все что они хотят. И сталкиваемся с непониманием — «ну это же сервак поднимать надо… это сложно… долго… дорого». В этой статье я продемонстрирую насколько быстро сейчас можно собрать бесплатное fullstack решение, способное обрабатывать http запросы, хранить данные и быстро показывать их изменение. Ну а чтобы статья была интересна максимальному кругу хабражителей, сервис выбран необычный, а стек технологий — самый, не побоюсь этого слова, трендовый. Кстати, в комментариях приветствуются обсуждения js vs python vs ruby, react vs angular vs ember и webpack vs browserify vs grunt vs gulp.
Подготавливаем toolchain
Устанавливаем последнюю версию node.js, регистрируемся на parse и устанавливаем себе их одноименную command line tool по инструкции. Установленный toolchain даст нам волшебную команду parse, с помощью которой можно не только создать новый проект, но и загрузить его в облако, и посмотреть логи. В общем, все как у всех.

Создаем приложение
Приложение создается командой parse new, которая позволит создать новое приложение или подключиться к существующему, и в случае создания нового приложения — создаст минимальный «скелет» в указанной директории. Созданное приложение можно сразу же загрузить в облако, выполнив в его директории команду parse deploy. Отгруженное в облако приложение будет доступно по url, которое нужно задать в настройках веб интерфейса, раздел «hosting»:

Созданный скелет приложения состоит из двух файлов: cloud/main.js для javascript кода и public/index.html для статики. Если мы зайдем на заданный нами url, то увидим как раз содержимое статичного html файла:

Добавляем немного express.js

Если сейчас запустить модифицированное приложение, то мы снова увидим содержимое index.html. Причина в том, что генератор добавил файлы экспресс, но не прописал их в «точке входа» main.js. Исправляем это упущение и меняем содержимое main.js на такой код:
require('cloud/app.js');
Обратите внимание, что при использовании поставляемых в комплекте библиотеки в require передается только имя библиотеки, а при загрузке ваших собственных файлов нужно прописывать путь от корня проекта. Такую реализацию require сделали ребята из parse, можно только догадываться зачем. В любом случае, загрузив новую версию приложения и перейдя по url /hello мы увидим работающий express.js
Переходим на typescript

В качестве такой системы я выбрал webpack — самое последнее решение, способное при удачном стечении обстоятельств не только организовать модули, но и заменить систему сборки, в роли которой обычно выступает grunt или gulp
Для установки компилятора typescript, webpack и ряда полезных утилит используем следующее заклинание node package manager (который обычно ставится вместе с node.js):
npm init
npm install typescript tsd webpack underscore ts-loader style-loader css-loader sass-loader node-sass --save
Чтобы typescript хорошо работал и проверял типы, нужно установить так называемые «type definitions» — описания типов для популярных библиотек, которые создаются и поддерживаются разработчиками. Делается это с помощью утилиты tsd, которую мы поставили вместе с компилятором:
tsd install express
tsd rebundle
Чтобы webpack собирал typescript, создадим для него конфигурационный файл webpack.config.js, единственный объемный кусок кода в моей демонстрации:
var _ = require('underscore');
var BASE_CFG = {
resolve: {
extensions: ['', '.js', '.ts', '.jsx', '.tsx'],
},
module: {
loaders: [
{test: /\.ts(x?)$/, loader: 'ts-loader'},
{test: /\.scss$/, loaders: ['style', 'css', 'sass']},
],
},
};
var BACKEND_CFG = _.extend({}, BASE_CFG, {
target: 'node',
entry: './src/backend.ts',
output: {
path: './cloud',
filename: 'main.js',
},
externals: {
'express': 'commonjs express',
},
});
module.exports = [BACKEND_CFG];
Теперь можно стереть все из папок public и cloud, заменив на единственный файл с кратким кодом бэкенда, src/backend.ts:
/// <reference path="../typings/tsd.d.ts" />
import * as express from 'express';
const app = express();
app.get('/', (req, res) => res.end("hello, habr!"));
app.listen(8080);
Краткость — сестра. Собираем и отгружаем в облако:
webpack
parse deploy
Добавляем ReactJS

npm install react --save
tsd install react --save
Добавим в конфигурацию webpack правила для сборки frontend части:
var FRONTEND_CFG = _.extend({}, BASE_CFG, {
target: 'web',
entry: './src/frontend.tsx',
output: {
path: './public',
filename: 'frontend.js',
},
ts: {
compilerOptions: {
'jsx': 'react',
},
},
});
module.exports = [FRONTEND_CFG, BACKEND_CFG];
И собственно сам код frontend в файле src/frontend.tsx, который так же будет написан на typescript (обратите внимание на расширение, гремучая смесь typescript и xml):
/// <reference path="../typings/tsd.d.ts" />
import * as React from 'react';
class Ui extends React.Component<any, any> {
render() {
return <div>helo, habr</div>;
}
}
document.addEventListener('DOMContentLoaded', () => {
React.render(React.createElement(Ui), document.body);
});
Чтобы React загрузился на фронтенде, немного модифицируем src/backend.ts:
app.get('/', (req, res) => {
res.end('<script type="text/javascript" src="frontend.js"></script>');
});
Все готово — собираем, загружаем в облако и видим заготовку пользовательского интерфейса на ReactJS. Которую можно очень быстро превратить в полноценный интерфейс с помощью готовых наборов компонентов
Добавляем SASS
Webpack — это не только конкурент Browserify, нехорошо поглядывающий на gulp. Это еще и возможность подключать через require файлы, отличные от javascript. Например — css стили. Или sass, что сейчас более популярно. У такого подхода есть плюсы и минусы, при этом плюсы лежат в области лучшей читаемости и организации кода, а минусы — в скорости загрузки того что получилось. Каждый выбирает под свои задачи, главное — чтобы было легко использовать. А с webpack подключение sass стилей становится вопросом одной строчки кода. Вот такой:
require("./frontend.scss");
Благодаря настойкам в конфигурационном файле webpack, указанный .scss файл будет преобразован в css, добавлен в виде текстовой строки в результирующий javascript и автоматически загружен в dom на клиенте. При необходимости процесс можно тонко подстроить под свои нужды и оптимизировать по скорости загрузки, но простейший случай решается ровно в одну строчку кода, что не может не радовать. Загруженные стили можно использовать в ReactJS в соответствии с синтаксисом JSX:
render() {
return <div className='ui'>styled hello, habr</div>
}
Заключение

К минусам следует отнести общую слабость хостинговой платформы: по моим ощущениям, все создавалось вокруг ORM, и возможности делать веб приложения и выполнять произвольный код в облаке были добавлены значительно позже. Голый V8 вместо node.js, невозможность установить большинство модулей и еще ряд ограничений не позволяют рассматривать parse как совсем универсальное решение. Но, тем не менее, для многих задач платформа подходит очень хорошо — что, я надеюсь, и было продемонстрировано в статье. Вопросы, уточнения, немного флейма в понедельник?
Комментарии (8)
Anisotropic
05.10.2015 11:32>react vs angular vs amber
Amber.js переименовали в Ember.js 4 года назад :)eyeofhell
05.10.2015 12:10+1Точно, это уже не первый раз когда я так опечатываюсь -_-. Хорошо хоть Qt пока правильно пишу :).
aylarov
05.10.2015 13:39+1TypeScript + React + Webpack отличное сочетание, еще бы в Sublime нормально работал плагин для TypeScript (подгружал type definitions без проблем)…
forcewake
05.10.2015 18:44+1Можете попробовать Atom с пакетом atom-typescript. Даже сейчас вполне юзабельно и вполне себе удобно использовать.
RUQ
Стоит сказать, что основной для javascript'ового API Parse служит Backbone. Но если хотите использовать его на 100%, то всё же необходимо подключить его отдельно (backbone). А в целом Parse очень крутое подспорье frontend-специалисту, помогает на ранних стадиях приложения обходится вообще без backend-части, соответственно экономятся силы и время.
В Parse есть всё для построения стандартных CRUD систем, кроме того есть api для работы с гео-объектами, файлами, упрощённая регистрация пользователей + facebook login.
eyeofhell
Плюсую, backbone там есть. Правда, не в чистом виде, а в виде форка, на котором построен их SDK для работы с ORM. Сделать require('backbone') в cloud code нельзя :)
kurtov
В недавней версии 1.6 решили отказаться от использование Backbone и развиваться своим путем.
«SDK no longer contains Backbone-specific behavior. Moving forward, the core SDK will not be tied to any single framework, but we will work with the community to produce up-to-date bindings like Parse+React. The major changes are the removal of Parse.Collection, and allowing Parse.Objects to act as event channels.»