Как устроена плагинация в Modus BI - Публичная база знаний Modus
Предпосылки и проблема предыдущего подхода
Modus BI — это система, построенная на основе React, Redux, Webpack, npm и библиотеки визуализаций, в частности, Amcharts, Echarts, D3 и т.п.
На фоне развития в Modus BI увеличивается количество поддерживаемых визуализаций. У некоторых заказчиков со временем возникает запрос на уникальные визуализации, не подходящие под общую постановку. Данный запрос закрывается механизмом плагинов (плагинация).
Ранее кастомизация для отдельных клиентов реализовывалась через отдельные git-ветки. Это приводило к разрастанию числа поддерживаемых веток, постоянным merge-конфликтам при переносе общих доработок и замедлению развития ядра продукта. Плагинация призвана устранить эти проблемы, позволяя подключать уникальную логику без форсирования ядра.
Перед реализацией плагинации стоял выбор архитектуры плагинации в зависимости от следующих требований:
- подключение плагина без пересборки в webpack;
- возможность разработки без раскрытия исходного кода ядра проекта;
- горячая загрузка плагинов: новый виджет должен быть доступен сразу после загрузки, без пересборки всего приложения.
Примечание — создан отдельный проект для разработки плагинов custom-chart, который опубликован в GitHub.
Архитектура плагинации: механизмы и реализация
В основе решения лежат два механизма: подмена модуля и externals.
Подмена модуля работает следующим образом. При сборке build ядра проекта в него включается модуль-заглушка — отдельный JS-файл, который не содержит функциональности, но поддерживает интерфейс плагина. Все такие файлы динамически подключаются через тег <script> в index.html. При загрузке плагина бэкенд перезаписывает этот модуль, и в сборку попадает новая функциональность и фронтенд начинает использовать новый код без перезагрузки всего приложения. Каждый модуль-заглушка порождает один слот. Число слотов определяет, сколько разных визуализаций могут одновременно присутствовать на портале. Всего зарезервирован 41 слот (от 0 до 40), при этом слот 0 выделен для разработки (при необходимости в новых релизах это число может быть увеличено).
Другим механизмом, на основе которого работает плагинация, является механизм externals — это функция webpack, который позволяет подключать ресурсы без пересборки проекта.
Чтобы проект мог собираться до загрузки плагинов, используются заглушки. При сборке основного приложения резервируются места под будущие плагины в виде пустых React‑компонентов — они служат точками подключения, куда позже подставляется код. Webpack настраивается так, чтобы он не включал плагины в основной бандл, а подключал их отдельно.
В качестве формата модуля externals выбирается UMD (JavaScript ), так как он обеспечивает наибольшую гибкость.
На схеме ниже слева показан запуск сервиса для ядра портала (сборка build), справа — для проекта разработки плагина (сборка prebuild). В средней части расположены ресурсы externals, которые являются третьей независимой стороной и могут внедряться в обе конфигурации.
Основой сборки в обеих конфигурациях является ядро портала. В основном проекте сборка называется build и создаётся каждый раз заново, в проекте разработки плагина — prebuild. Результат сборки плагина попадает в сборку ядра как встроенный элемент через механизм подмены.
ComponentType Manager и его модули
ComponentType Manager — модуль композиции функционала для типов визуализаций. Он получает как аргумент тип визуализации и позволяет через свои методы обращаться к различным модулям, в которых собирается функционал визуализаций.
Ниже список модулей, с которых собирается функционал визуализаций:
- DataAdaptor — отвечает за преобразование данных, полученных от бэкенда. На выходе структура плот-данных (plot data), которая уже полностью готова к рендерингу;
- ChartAdaptor и SpecGenerator;
- ConfigEditor — модуль, который управляет поведением панели осей в редакторе компонента.
Примечание — SpecGenerator и ChartAdaptor работают в связке. Используются в типах диаграмм, построенных на какой-либо библиотеке визуализаций, например, на Amcharts, Echarts. SpecGenerator генерирует спецификацию — это, по сути, JSON, описывающий как строить визуализацию. А ChartAdaptor переводит спецификацию в вызов методов уже непосредственно библиотеки визуализаций, после этого происходит рендеринг.
На рисунке ниже представлена композиция функционала в файле ComponentTypeManager.js:

Модули встройки в Plugins API
Модули встройки являются основой для реализации плагинов в Plugins API. Plugins API определяет строгий контракт, которому должен следовать каждый плагин: он обязан экспортировать четыре ключевых компонента:

- CustomChart — это область рендеринга самой визуализации, корневой компонент визуализации, отвечающий за отображение виджета на дашборде;
- CustomSettings — настройка, отвечающая за интерфейс настроек;
- CustomReducers — это настройка, отвечающая за обработку вызываемых в настройках экшенов. При этом CustomReducers — это Redux-экшен (функция, которая описывает, как изменяется состояние в Redux-хранилище) для интеграции с Redux;
- CustomAxes — панель осей (так называемые «полки») или, по-другому, конфигурация для работы с данными в конструкторе.
Код плагина организован в папке modules, где каждый модуль встройки выделен в отдельную группу. В папке duplicates содержится референсный код, который можно использовать без изменений или взять за основу для собственной реализации, поместив её в modules. Внутри папки managers находится ComponentType Manager, который выполняет декомпозицию функционала аналогично тому, как это сделано в ядре проекта.
В файле index.js можно посмотреть, как собирается экспортируемый объект. Помимо модулей встройки, в этот объект включаются также DataAdaptor, SpecGenerator и ConfigEditor — все они перечислены в разделе экспорта pluginsAPI.
В разделе импортов pluginsAPI передаются не только стандартные пропсы, имеющие аналоги в ядре, но и специальный объект pluginImports. Через него предоставляются три типа ресурсов:
- components — стандартные элементы интерфейса, например, SettingsToggle;
- sections — целые секции интерфейса, которые используются вообще без какой-либо параметризации, например, это целиком раздел «Рамка компонентов» в настройках визуализации, одинаковый для всех типов диаграмм;
- helpers — служебные функции.

Примечание — вы можете ознакомиться с примером создания плагина в разделе «Инструкция по созданию плагина визуализации (с примерами кода из готового проекта)».