Jii: Полноценное приложение с архитектурой Yii2 в браузере

Привет всем хабровчанам, любителям Yii и Node.js. Продолжаю серию статей про Jii, на сей раз настала очередь рассказать о том, что Jii можно использовать в браузере.

f52ecc71f8794a43a8a4b66983541f60.jpg


Представьте, уже сейчас все структуры фреймворка, такие как приложения, компоненты, контроллеры, модули, модели, представления доступны в браузере!
Для тех, кто в первый раз слышит об этом фреймворке, рекомендую прочитать предыдущие статьи или посетить сайт. Если коротко, то

Jii — это фреймфорк, архитектура и API которого базируется на PHP фреймворке Yii 2.0, взяв из него лучшие стороны и сохраняя приемущества JavaScript.


Jii на клиенте (в браузере)


Jii изначально пишется так, чтобы его можно было использовать везде, где может выполняться JavaScript код. Если код модуля не завязан на серверной инфраструктуре, то его можно использовать в браузере.

Все это разбито и подключается по частям, в видел npm модулей:

  • jii (или jii/deps) — базовые классы и основа фреймворка;
  • jii-clientrouter — Роутер, запускающий действия при изменении адресной строки; Работает совместно с jii-urlmanager;
  • jii-comet — Комет клиент;
  • jii-model — Модель набором валидаторов (которые указываются в rules());
  • jii-urlmanager — Разбор url, получение route на основе указанных правил;
  • jii-view — Рендер представлений.


Создание приложения на клиенте


Создаваться приложение будет почти также как и серверное:

// Libs
require('jii/deps'); // included underscore and underscore.string libraries
require('jii-urlmanager');
require('jii-clientrouter');

// Application
require('./controllers/SiteController');

Jii.createWebApplication({
    application: {
        basePath: location.href,
        components: {
            urlManager: {
                className: 'Jii.urlManager.UrlManager',
                rules: {
                    '': 'site/index'
                }
            },
            router: {
                className: 'Jii.clientRouter.Router'
            }
        }
    }
}).start();

console.log('Index page url: ' + Jii.app.urlManager.createUrl('site/index'));


Зависимости


6adf9206a6f54d438c20c100dc5de5f1.jpg


Jii имеет зависимости от библиотек Underscore и Underscore.string. Если они уже подключены у вас на странице, то нужно подключать Jii как require('jii'), если зависимости нужны — require('jii/deps').

Компиляция JavaScript кода


Jii рекомендует использовать CommonJS подход для подгрузки зависимостей. Сборку модулей можно делать любыми средствами, например, используя Browserify. Рассмотрим простейший пример сборки.
Установка зависимотей:

npm install --save-dev gulp gulp-easy


Файл gulpfile.js:

require('gulp-easy')(require('gulp'))
    .js('sources/index.js', 'bundle.js')


Роутинг на клиенте


03ce3f9a7f994ba481528e569ff2fd9b.jpg


Когда необходимо следить и обрабатывать состояние адресной строки браузера, в бой вступает модуль jii-clientrouter, предназначенный именно для этой цели.
Jii-clientrouter устанавливается как компонент приложения и подписывается на событие popstate (или hashchange для браузеров, не поддерживающих HTML5 History API).

При загрузке страницы или изменении адресной строки запускается обработчик, который парсит адресную строку компонентом Jii.urlManager.UrlManager, получает route с параметрами запроса и запускает действие (action), эквивалентное найденному route. Поэтому для работы Jii-clientrouter необходимо так же подключить jii-urlmanager.

Пример конфигурации приложения:

require('jii/deps');
require('jii-urlmanager');
require('jii-clientrouter');

// Application
window.app = Jii.namespace('app');
require('./controllers/SiteController');

Jii.createWebApplication({
    application: {
        basePath: location.href,
        components: {
            urlManager: {
                className: 'Jii.urlManager.UrlManager',
                rules: {
                    '': 'site/index',
                    'article/<id>': 'site/article',
                }
            },
            router: {
                className: 'Jii.clientRouter.Router'
            },

            // ...
        }
    }
}).start();


В действии будут доступны компоненты request (Jii.clientRouter.Request) и response (Jii.clientRouter.Response), как это было при работе на сервере с HTTP сервером. Используя эти компоненты, можно получить параметры из адресой строки. Рассмотрим небольшой пример такого действия.

Предположим, что у нас адресная строка содержить адрес localhost:3000/article/new-features, тогда при переходе на заданный адрес на клиенте сработает обработчик Jii.clientRouter.Router._onRoute(), который найдет роутер site/article и запустит действие (метод) actionArticle() контроллера app.controllers.SiteController:

/**
 * @class app.controllers.SiteController
 * @extends Jii.base.Controller
 */
Jii.defineClass('app.controllers.SiteController', /** @lends app.controllers.SiteController.prototype */{

        __extends: Jii.base.Controller,

        // ...

        actionArticle: function(context) {
            console.log(context.request.getQueryParams()); // {id: 'new-features'}
        }

});


Демо


Пример использования Jii в браузере можно посмотреть на Github в исходниках примитивного чата — jiisoft/jii-boilerplate-chat.

Не стоит воспринимать данный пример как «лучшие практики» использования Jii, так как эти практики еще не сформировались. Я буду рад услышать рекомендации по оформлению и структуре кода на клиенте.

В заключении


4854fe9970ff49a69ebf9a069478ec1e.jpg


Напомню, Jii — опенсорсный проект, поэтому я буду очень рад, если кто-то присоединится к его разработке. Пишите на affka@affka.ru.

Сайт фреймворка — jiiframework.ru
GitHub — https://github.com/jiisoft
Обсуждение фич проходит на гитхабе

Нравится идея фреймворка? Ставь звезду на гитхабе!


Навигация по статьям

© Habrahabr.ru