Вступление

ZombieBox — JavaScript-фреймворк для разработки под SmartTV и STB–приставки, со следующими возможностями:

  1. Кроссплатформенная разработка — запуск единожды написанного приложения на различных платформах SmartTV и STB;
  2. Облегчение рутинных задач при разработке под SmartTV и STB.

ZombieBox состоит из:

  • Абстракции над платформой;
  • Фреймворка;
  • Компонент;
  • Инструментов разработчика.

Для достижения максимальной скорости работы низкопроизводительных платформах SmartTV и STB используется нативный JavaScript без использования ресурсоёмких библиотек.

Поддерживаемые платформы:

  • Samsung Smart TV,
  • Samsung Tizen,
  • LG NetCast Smart TV,
  • LG webOS Smart TV,
  • Dune HD STB,
  • Mag/Aura HD STB,
  • Eltex STB,
  • TVIP STB.

Начало работы

Требования:

  • Node.js;
  • NPM.

Для начала разработки на ZombieBox нужно выполнить глобальную установку пакета zombiebox-cli, который является утилитой, обеспечивающей сборку, развёртывание и генерацию boilerplate-кода. Установка производится командой npm -g install zombiebox-cli.

После нужно перейти в директорию будущего проекта и создать "каркас" приложения командой zb init, задавая параметры при помощи интерактивной настройки.

Дальнейшим шагом будет установка зависимостей с помощью команды npm install и последующий запуск web-based приложения с помощью команды zb run. По умолчанию адресом будет http://localhost:1337.

Основные понятия

ZB-фреймворк (ZB-framework)

Набор взаимосвязанных компонентов, обеспечивающих комфортную кроссплатформенную разработку.

Фреймворк предоставляет следующие возможности:

  • Управление композицией слоёв представлений;
  • Сохранение состояний слоёв;
  • Пространственная навигация;
  • История переходов;
  • Инструменты для выполнения асинхронных запросов и управления моделями данных;
  • Обработка ввода.

Платформа (Platform)

Платформа — это npm-пакет, имеющий префикс zombiebox-platform- (например, zombiebox-platform-lg), состоящий из компонентов, реализующих интерфейсы абстрактной платформы. Чтобы подключить платформу к приложению следует указать её в package.json в разделе dependencies.

Инструменты разработчика (Development tools)

Утилита командной строки zb — отправная точка для начала работы с ZombieBox. Выполняет инициализацию проекта, запускает приложение, создаёт артефакт для публикации на конкретной платформе и так далее.

Файлы шаблонов (Template files)

Файлы шаблонов — это файлы с расширением .jst. "Из коробки" используется шаблонизатор CuteJS, специально спроектированный для удобного взаимодействия с ZombieBox и предоставляющий широкий диапазон возможностей. Подробнее ознакомиться с данным шаблонизатором можно на npmjs.com/package/cutejs.

Лог-cервер (Log-server)

Лог-cервер — это npm-пакет zb-log-server, предоставляющий возможность "слушать" входящие лог-сообщения от ZombieBox-приложения. Лог-сервер в связке с входящим в состав фреймворка remote-логгером позволяет осуществляет удалённую отладку.

В случае использования web-based приложения, нет необходимости запускать отдельный лог-сервер. Веб-сервер, запущенный командой zb run, принимает входящие лог-сообщения по адресу http://localhost:%port%/log.

Инструменты разработчика

Консольные команды

zb init

Инициализация проекта с интерактивным вводом параметров, необходимых для создания изначальной структуры директорий и файлов. Создаёт директории .code-cache, app, dist, web, а также директории для сцен, попапов, виджетов, класс глобального объекта приложения (application.js) и начальный файл стилей (application.css).

zb build [platform list] [--enableConsole]

Сборка приложения для публикации под конкретные платформы (можно указать несколько через знак пробела).

Процесс сборки можно условно разделить на два шага:

  • Компиляция исходного кода;
  • Передача обработки платформе — создание специфичных артефактов или осуществление обработки скомпилированного кода, например создание файлов конфигурации платформы, преобразование исходного кода, архивирование и т.д.

При сборке доступен опциональный флаг активации логирования (--enableConsole), при наличии которого все лог-сообщения будут обработаны, в противном случае — проигнорированы.

Путь до артефакта сборки: dist/%application_version%/%platform_name%/index.html. Там же могут находится артефакты, созданные самой платформой.

Для процесса сборки существует возможность создания хуков. Для этого следует создать в корневом каталоге файлы prebuild.js и postbuild.js для обработки до компиляции и после, соотвественно. Файлы хуков должны быть node-модулем и принимать на вход функцию обратного вызова процесса и объект данных сборки.

В процессе компиляции все JS-файлы приложения, а также фреймворка и платформы будут сжаты и оптимизированы с требуемым уровнем оптимизации (по умолчанию ADVANCED_OPTIMIZATIONS) с помощью GCC, CSS-файлы будут минифицированы, а ссылки на изображения, содержащиеся в CSS, заменены на base64.

zb run

Запускает web-based приложение, доступное по умолчанию по адресу http://localhost:1337 и являющееся платформонезависимым. То есть, приложение автоматически распознает текущую платформу, основываясь на перечне подключённых платформ, и использует её в процессе работы.

При данном виде разработки не происходит полноценной сборки приложения, то есть, исходный код всегда будет актуальным, без необходимости осуществлять дополнительные действия, когда вносятся изменения. Дополнительно актуализировать исходный код помогают наблюдатели за изменениями файлов, запускающиеся вместе с сервером и реагирующие на изменениями в .jst и .css файлах. При наличии изменений происходит перекомпиляция шаблонов и создание CSS-префиксов.

Также для web-based приложения есть возможность кастомизировать исходный код с помощью файла web/dev.js. Его включение происходит после всех основных файлов, но перед точкой входа в приложение, тем самым давая возможность заменить любой метод или задать специфичную конфигурацию. Обычно данный файл добавляется в .%choose_your_scv%ignore.

zb buildCode

Генерирует boilerplate-код приложения, компилирует файлы шаблонов, создаёт CSS-префиксы, позволяющие забыть о проблемах кроссбраузерности CSS-кода.

Генерируемый boilerplate-код находится в директории .code_cache и влючает в себя скомпилированные шаблоны, а также следующие файлы:

  • index.js — точка входа (entry point). Инстанцирует глобальный объект приложения, который будет доступен из глобальной переменной app;
  • base-application.js — содержит класс, наследником которого является глобальный объект приложения. В него инкапсулирована логика по определению платформы и регистрация сцен (сцены, имеющие префикс abstract-, не регистрируются);
  • package-info.js — содержит информацию о приложении;
  • resolutions.js —  конфигурирует разрешения экрана для платформы;
  • autoprefixer.css — сгенерированные префиксы для CSS-файлов.

В случае запуска web-based приложения командой zb run или сборки под платформу командой zb build, нет необходимости в выполнении этой команды, так как она является частью соответствующего процесса.

zb addScene, zb addPopup, zb addWidget [name] [--base %baseclass%]

Генерирует boilerplate-код для выбранной сущности. Параметр name может содержать несколько значений, разделённых пробелом, так, например, при вызове zb addWidget my darling widget будет сгенерирован виджет %project_namespace%.widgets.MyDarlingWidget.

zb-log-server

Поднимает сервер, который слушает входящие логи.

Абстракция над платформой

ZombieBox предоставляет абстракцию над платформой, обеспечивая кроссплатформенную разработку — единожды написанный код будет работать на всех требуемых платформах.

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

Абстракция над платформами предоставляет следующие интерфейсы:

  • ZBPlatform — входная точка для платформы, отвечает за сборку, конфигурирование и передачу реализованных компонентов в процесс сборки приложения;
  • IDevice — основной компонент платформы, инкапсулирует в себя остальные компоненты, содержит логику по обработке OSD, отвечает за создание видео-объекта, инициализацию и выход из устройства;
  • IInfo — предоставляет информацию об устройстве. Например, серийный номер, модель, версия программного обеспечения и т.д.;
  • IInput — отвечает за обработку нажатий кнопок и перемещение курсора (если поддерживается) устройств ввода;
  • IStorage — предоставляет возможность сохранения данных на клиентском устройстве, сохраняющиеся между запусками приложения;
  • IVideo – видео-объект, реализует API по управлению потоком, воспроизведением, громкостью, пропорциями и соотношением сторон. Обеспечивает транслирование событий по воспроизведению видео потока;

Компоненты

В состав фреймворка входят следующие готовые компоненты:

  • Video controls
  • Video progress bar
  • Button
  • Throbber
  • Input
  • Keyboard
  • Help bar
  • Google analytics tools
  • Scrolled list
  • Linear list with navigation
  • Grid with navigation

Фреймворк

Архитектура приложения

Приложение (Application)

Глобальный объект приложения, который инстанцируется в точке входа и доступен из глобальной переменной app. Наследуясь от сгенерированного boilerplate-класса, он реализует определение платформы и первоначальную регистрацию сцен.

Представление (View)

  • Контейнер (Container) — объект, который является контейнером для виджетов. Реализует пространственную навигацию по помещённым в него виджетам. При наступлении события навигации передвижение курсора или нажатие навигационных кнопок на пульте) перемещает фокус на подходящий виджет;
  • Слой (Layer) — контейнер, основной элемент DOM'a. Слоем может быть сцена (scene) или попап (popup). Может содержать дочерние слои;
  • Виджет (Widget) — контейнер, помещающийся в слой. Управляет своим состоянием и видимостью. Также содержит методы beforeDOMShow, afterDOMShow, beforeDOMHideafterDOMHide, которые вызываются либо из слоя, куда включён виджет, либо при изменении видимости.

Модель (Model)

Для структурного представления используются модели (models). Модель (AbstractModel) используется как контейнер для хранения данных, с распространением события при изменении хранимых данных (EVENT_CHANGE).

Управление слоями

Управлением слоями занимается менеджер слоёв (LayerManager). Регистрирует слои, которые соответствующим образом обрабатываются. Так, например, при инициализации в нем регистрируются сцены, с помощью метода addScene.

Глобальный объект приложения предоставляет следующие методы, которые делегируют действия к менеджеру слоёв:

  • addScene — регистрирует сцену по указанному имени;
  • show — открывает зарегистрированную сцену по указанному имени, также принимает на вход объект данных, с которым будет вызван метод preload;
  • home – открывает домашнюю сцену.

Включение слоя в DOM осуществляется при регистрации сцены или вручную, с помощью метода app.showChildLayer или app.showChildLayerInstance, принимающие конструктор или инстанс слоя соответственно.

В процессе обработки менеджером слоёв (LayerManager) выполняются методы, дополнением которых можно проконтролировать процесс обработки слоя:

  • preload — принимает объект данных и возвращает Promise. Вызывается перед показом слоя. Показ сцены осуществится только когда Promise разрешится. Используется, когда слою требуются внешние данные, нередко подгружаемые асинхронным запросом;
  • update — принимает снэпшот (snapshot) и объект данных из истории переходов, возвращает Promise. Вызывается при перемещении назад по истории переходов. Показ сцены осуществится только когда Promise разрешится. Используется, когда нужно обновить данные, хранящиеся в истории переходов;
  • beforeDOMShow — принимает снэпшот и объект данных.  Вызывается после preload, но перед тем, как показать слой. Вызывает beforeDOMShow для всех своих виджетов;
  • afterDOMShow — принимает снэпшот и объект данных. Вызывается после показа слоя. Вызывает afterDOMShow для всех своих виджетов. При наличии снэпшота загружает его, в противном случае активирует виджет по умолчанию (если такой установлен);
  • beforeDOMHide — вызывается перед скрытием слоя. Вызывает beforeDOMHide для всех своих виджетов;
  • afterDOMHide — вызывается после скрытия слоя. Вызывает afterDOMHide для всех своих виджетов.

Пространственная навигация

Навигация осуществляется одним из двух способов:

  1. Проверяется наличие подходящего правила перехода. Правило перехода задаётся с помощью метода setNavigationRule, в который передаётся виджет, с которого осуществляется переход, направление, виджет на который осуществляется переход, а также необязательный флаг двунаправленности, при наличии которого будет справедливо обратное правило для данного перехода;
  2. Если подходящего правила перехода не найдено, задействуется пространственная навигация. В этом случае подходящий виджет определяется на основании положения предыдущего виджета.

Виджеты, помещённые в контейнер, также являются контейнерами и могут содержать другие виджеты. В связи с этим иногда может потребоваться задать виджет по умолчанию, который будет активирован в случае, когда предыдущего активного виджета ещё нет. Это делается с помощью метода setDefaultWidget, который принимает инстанс виджета и делает его виджетом по умолчанию.

В целях отладки существует возможность активации debug-режима с помощью setNavigationDebug. В этом случае в процессе навигации границы виджетов будут подсвечиваться разными цветами:

  • Красный — предыдущий виджет, который находился в фокусе до наступления события навигации;
  • Зелёный — текущий виджет в фокусе;
  • Серый — все остальные виджеты, попавшие в область навигации.

Управление историей переходов

Управлением историей переходов занимается менеджер истории (HistoryManager). История представляет собой список записей истории (history record). Каждая запись содержит ссылку на объект сцены, которой она принадлежит, снэпшот, а также объект данных, с которым она была загружена.

Глобальный объект приложения предоставляет следующие методы, которые делегируют действия к менеджеру истории:

  • clearHistory — очищает все существующие записи истории;
  • back – движение назад по записям истории. В случае окончания истории переходов — выполняется выход из устройства. Так как выполняется показ сцены, который может занять время, на этот период компонент ввода устройства (IInput) блокируется, после того как сцена будет показана — ввод разблокируется;
  • forward – движение вперёд по записям истории. При этом также блокируется ввод.

Сохранение состояния

Снэпшот (Snapshot) — объект, который содержит в себе состояние, сделавшего его слоя, а также снэпшоты всех виджетов, включённых в слой. Состоянием могут являться данные любого типа, которые помогут на их основании актуализировать слой.

Перед тем, как скрыть слой, менеджер истории делает снэпшот и сохраняет его в записи истории. При последующем открытии слоя, сохранённый снэпшот передаётся в метод afterDOMShow, где он потом загружается и устанавливает состояние слоя и его виджетов.

Так как и слой и виджеты — это контейнеры, чтобы осуществить сохранение и применение состояния, достаточно переопределить методы saveState и loadState, которые являются частью API контейнера.

Обработка ввода

Обработка нажатий кнопок пульта осуществляется по принципу всплытия событий (event propagation). Местом зарождения события является InputDispatcher, который в результате взаимодействия с компонентом ввода платформы (IInput) производит обработку событий нажатия. При наступлении соответствующего события, внутренний код нажатой кнопки переводится в унифицированный код фреймворка и дальше передаётся на обработку глобальному объекту приложения.

Глобальный объект приложения затем запускает погружение события нажатия по иерархии композиции слоёв. Вначале будет вызван метод processKey у текущей сцены, которая при наличии в ней дочерних слоёв, вызовет processKey у верхнего дочернего слоя (top child layer), в противном случае передаст обработку нажатия своему активному виджету, а тот своему и т.д. Если событие не обработано в процессе погружения, то виджет по умолчанию вызывет метод _processKey, в котором производит обработку событий связанных с его собственной логикой. В базовой реализации виджет обрабатывает в методе _processKey события кнопок навигации (UP, DOWN, LEFT, RIGHT). В случае, если ни на одном из уровней погружения событие не было обработано, вызывается метод _processKey уже непосредственно у самого глобального объекта приложения, который в случае, если нажата кнопка BACK, выполнит перемещение по истории записей назад.

Так же InputDispatcher отвечает за обработку курсора, если он поддерживается устройством. Для этого контейнер, после передачи в него виджета, с помощью InputDispatcher назначает обработчики на события мышки DOM элемента виджета (mouseover, click, mousewheel), при наступлении которых, виджет обрабатывает его соответствующим образом. Так, например, на событие mouseover виджет активируется, а на событие click — сэмулирует нажатие на него кнопки ENTER.

Выполнение асинхронных запросов

В состав фреймворка входит компонент Transport, который реализует сохраняемый запрос (persistent request). Это значит, что при неуспешном выполнении (promise of query was rejected) сценарий может пойти по трём путям: повтор запроса, отмена или выход из устройства. Для этого ему передаётся обработчик, который должен вернуть один из трёх кодов состояния. Таким обработчиком может быть, например, показ попапа, который разрешится с соответствующим кодом по нажатию одной из его кнопок.

Запуск приложения

После инстанцирования в точке входа, приложение проходит следующие стадии:

  • Создание глобального DOM — сюда входят контейнеры для видео-объекта, слоёв, системный контейнер, контейнер для плагинов устройства. Контейнер — это простой HTMLDivElement;
  • Файрится событие EVENT_DOM_READY;
  • Выбор платформы и инициализация устройства;
  • Файрится событие EVENT_DEVICE_READY;
  • Инициализируются менеджеры истории и слоёв, InputDispatcher, к DOM'у применяется разрешение экрана;
  • Вызывается метод onReady — он может быть переопределён и нужен в том случае, если необходимо выполнить какие-то действия до регистрации сцен;
  • Регистрируются сцены приложения;
  • Вызывается метод onStart — также переопределяется. Здесь может находиться процесс открытия домашней сцены с помощью метода home, если предварительно были установлены её имя и необязательный объект данных (setHomeScene) или альтернативные действия.

Логирование

Логирование реализуется несколькими способами, за каждый из которых отвечает свой тип логгера:

  • Вывод в консоль (Console);
  • При помощи модального окна (Alert);
  • Методом отправки лог-сообщений на удалённый сервер (Remote).

Каждый тип логгера реализует интерфейс ILogger, тем самым возможно создание собственных вариантов логирования.

Есть возможность назначить требуемый уровень логирования. В этом случае, если вызываемый метод логгера не удовлетворяет текущему уровню, его вызов будет проигнорирован. Доступные уровни: ALL, LOG, DEBUG, INFO, WARN, ERROR, ASSERT, DIR, TIME.

Процесс и конфигурирование осуществляются с помощью объекта zb.console со следующим API:

  • zb.console.[log|debug|info|warn|error|assert|dir] — логирование с соответствующим уровнем. В случае типа Console соответствующие методы заменяются на нативные браузерные;
  • zb.console.[time|timeEnd] — управление таймером;
  • zb.console.setLevel — устанавливает требуемый уровень логирования. Содержит маску, полученную путём применения побитового ИЛИ к набору уровней. Например: zb.console.setLevel(zb.console.Level.LOG | zb.console.Level.DEBUG);
  • zb.console.setLogger — устанавливает тип логирования. Принимает инстанс логгера, реализующий интерфейс ILogger.

Концепции

ZombieBox любит:

  • Событийно-ориентированную модель взаимодействия;
  • Использование Promise;
  • Соглашение об именовании: в файлах — разделять слова с помощью тире, в коде — использовать верблюжий регистр;
  • ...
  • PROFIT!

Конфигурация

Конфигурация для сборки приложения должна находиться в файле config.js, который создается при первоначальной инициализации.

Параметры конфигурации (в скобках - значение по умолчанию):

  • web.port (1337) - порт web-based приложения;

  • web.proxy ({}) - представляет собой пары ключ-значение, где ключ - адрес, по которому будет доступен проксируемый адрес, значение - проксируемый адрес;

  • web.enableRawProxy (false) - если это значение true, то адрес proxy/?url=%url% будет проксировать адрес %url%;

  • scripts ([defaults]) - JS файлы, включаемые в сборку;

  • styles ([]) - CSS файлы, включаемые в сборку;

  • platforms (['pc']) - DEPRECATED;

  • compilation.level (ADVANCED_OPTIMIZATIONS) - уровень оптимизации GCC;

  • compilation.externs ([]) - внешние файлы для включения в процесс компиляции GCC;

  • compilation.exclude ([defaults]) - игнорируемые файлы в процессе компиляции GCC;

  • templateLocations ([defaults]) - список путей в которых искать шаблоны файлов. По умолчанию директория templates в проекте и в корне zombiebox пакета;

  • resolutions ([defaults]) - разрешения экрана.

Кроме хранимого в репозитарии config.js, в проекты ZombieBox могут добавляться индивидуальные для каждого разработчика dev.config.js. ZombieBox проверяет наличие файла dev.config.js, и в случае существования замещает указанные там параметры:

  • Для webOS указывается локальный путь до ares-package, что позволяет получать сразу готовый ipk файл после выполнения zb build webOS. Пример есть в README.md в zombiebox-platform-webos;
  • Для Samsung там указывается ip адрес веб-сервера, который подставляется в widgetlist.xml после выполнения zb build samsung. Пример есть в README.md в zombiebox-platform-samsung

Так же возможность замещать конфигурацию имеет платформа, реализуя метод getConfig.

Конфигурация

Конфигурация для сборки приложения должна находиться в файле config.js, который создаётся при первоначальной инициализации.

Параметры конфигурации (в скобках — значение по умолчанию):

  • web.port (1337) — порт web-based приложения;

  • web.proxy ({}) — представляет собой пары ключ-значение, где ключ — адрес, по которому будет доступен проксируемый адрес, значение — проксируемый адрес;

  • web.enableRawProxy (false) — если это значение true, то адрес proxy/?url=%url% будет проксировать адрес %url%;

  • scripts ([defaults]) — JS-файлы, включаемые в сборку;

  • styles ([])CSS-файлы, включаемые в сборку;

  • platforms (['pc']) — DEPRECATED;

  • compilation.level (ADVANCED_OPTIMIZATIONS) — уровень оптимизации GCC;

  • compilation.externs ([]) — внешние файлы для включения в процесс компиляции GCC;

  • compilation.exclude ([defaults]) — игнорируемые файлы в процессе компиляции GCC;

  • templateLocations ([defaults]) — список путей в которых искать шаблоны файлов. По умолчанию директория templates в проекте и в корне ZombieBox-пакета;

  • resolutions ([defaults]) — разрешения экрана.

Кроме хранимого в репозитарии config.js, в проекты ZombieBox могут добавляться индивидуальные для каждого разработчика dev.config.js. ZombieBox проверяет наличие файла dev.config.js, и в случае существования замещает указанные там параметры:

  • Для webOS указывается локальный путь до ares-package, что позволяет получать сразу готовый ipk-файл после выполнения zb build webOS. Пример есть в README.md в zombiebox-platform-webos;
  • Для Samsung там указывается ip-адрес веб-сервера, который подставляется в widgetlist.xml после выполнения zb build samsung. Пример есть в README.md в zombiebox-platform-samsung.

Так же возможность замещать конфигурацию имеет платформа, реализуя метод getConfig.

Рецепты

Changelog

Dependency Injection Container

В фрэймворке присутствует dependency injection container (DIC). Он автоматизирует инстанцирование сервисов приложения и внедрения в них необходимых зависимостей

Сервисы

Сервисы создаются на базе конфига проекта. Есть два способа конфигурации сервесов Конфигурация отдельных сервисов вручную Конфигурация автоматического поиска классов сервисов

Конфигурация вручную

Для конфигурации сервисов ипользуется ключ конфига проекта services Он должен содержать объект, ключи которого - имена сервисов, а значения - объекты определяющие способ инстанцирования сервиса (класс) и зависимости сервиса

специальные ключи:

специальне ключи этого объекта начинаются с подчерка

  • _class - (обязательный) класс который будет инстанцирован
  • _group - (опциональный) группа к которой будет отнесен сервис

зависимости:

остальные ключи задают параметры и зависимости сервиса зависимость может быть указана как конкретный сервис по имени, используя @servicename например, repositoryMovie: '@repositoryMovie'

или укзан класс/интерфейс по которому будет автоматически подобран сервис {full.class.Name} например, sceneMovieCard: '{sandbox.scenes.MovieCard}'

например javascript config = { services: { controllerMovie: { _class: 'sandbox.controller.MovieController', _group: 'controller', sceneMovieCard: '{sandbox.scenes.MovieCard}', sceneMovieList: '{sandbox.scenes.MovieList}', repositoryMovie: '@repositoryMovie' } } };

здесь: controllerMovie - имя сервиса _class: 'sandbox.controller.MovieController' - сервис будет создан как экземпляр класса sandbox.controller.MovieController sceneMovieCard: '{sandbox.scenes.MovieCard}' - зависимость sceneMovieCard указана классом sandbox.scenes.MovieCard сервис, который в нее будет инжектится будет подобран автоматически при матчинге зависимостей repositoryMovie: '@repositoryMovie' - зависимость repositoryMovie указана сервисом repositoryMovie в нее будет инжектится сервис с указанным именем

Автоматичский поиск

Папки для автоматического поиска сервисов указываются в конфиге проекта, в ключе servicesAutodetect

В конфиг по-умолчанию включены папки scenes и service

Папка может быть указана строкой или структурой

{{ group: string, namespace: string, directory: string }}

Если указана строка, то group получает значение этой строки, а namespace и directory достраиваются из нэмспэйса проекта и директории приложения проекта соответственно

Внутри этих папок ищутся конкретные классы, соответствующие zombiebox конвенции именования и создается по одному сервису для каждого класса. Зависимости этих сервисов определяются автоматически. Сервисы, которые будут инжектится в эти зависимости определяются в процессе матчинга.

Определение зависимостей

Автоматическое определение зависимостей используется для создания списка зависимостей автоматически найденных сервисов определения спосба инжекта зависимостей описанных вручную

Определяются зависимости, описанные несколькими способами

Propertis

Публичные проперти сервиса с аннотацией типа в которой описание начинается с пометки :inject

например: javascript /** * @type {sandbox.scenes.MovieList}:inject */ sandbox.controller.MovieController.prototype.sceneMovieList;

ES6 Properties

Публичные проперти, инициализируемые в конструкторе класса с аннотацией типа в которой описание начинается с пометки :inject

например: javascript sandbox.controller.MovieController = class { constructor() { /** * @type {sandbox.scenes.MovieList}:inject */ this.sceneMovieList = null; } }

Setters

Методы-сеттеры с аннотацией параметра в которой описание начинается с пометки :inject

например javascript /** * @param {sandbox.scenes.MovieList} sceneMovieList :inject */ sandbox.controller.MovieController.prototype.setSceneMovieList = function(sceneMovieList) { this._sceneMovieList = sceneMovieList; };

Конструктор

Параметры конструктора с аннотацией в которой описание начинается с пометки :inject

например javascript /** * @constructor * @param {sandbox.scenes.MovieList} sceneMovieList :inject * @param {sandbox.scenes.MovieCard} sceneMovieCard :inject */ sandbox.controller.MovieController = function(sceneMovieList, sceneMovieCard) { this._sceneMovieList = sceneMovieList; this._sceneMovieCard = sceneMovieCard; };

например (es2015 class) javascript sandbox.controller.MovieController = class { /** * @param {sandbox.scenes.MovieList} sceneMovieList :inject * @param {sandbox.scenes.MovieCard} sceneMovieCard :inject */ constructor(sceneMovieList, sceneMovieCard) { this._sceneMovieList = sceneMovieList; this._sceneMovieCard = sceneMovieCard; } }

Матчинг зависимостей

Если значение зависимости указано классом или интерфейсом и в DIC присутствует сервис класса подходящего для зависимости, он будет туда установлен. Подходящим считается

  • Класс, указанный в типе зависимости
  • Класс, наследующийся от указанного в типе зависимости
  • Класс, реализующий интерфейс указанный в типе зависимости

(!) Если подходят нескольки сервисов - нет гарантии того, какой из них будет использоваться инжектором

Механизм работы

При построении .code-cache приложения производится анализ структуры каталогов и содержания файлов соответственно описанным выше признакам и таким образом определяется схема компонентов приложения

В .code-cache генерируется файл с базовым классом сервис-контейнера, содержащий код инстанцирования сервисов и внедрения зависимостей в методе .bootstrap

В хуке onReady базового класса приложения инстанцируется сервис-контейнер и вызывется его метод .bootstrap

(!) при переопределении хука в классе приложения, не забудьте вызвать его базовую реализацию

Текущие ограничения

  • Отсутствует фаза инициализации
  • Системные сервисы исторически агрегируются в классе приложения, а не сервис-контейнера