1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/lorrychen-minimajs

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
Клонировать/Скачать

A permissive license whose main conditions require preservation of copyright and license notices. Contributors provide an express grant of patent rights. Licensed works, modifications, and larger works may be distributed under different terms and without source code.

Permissions
  • Commercial use
  • Modification
  • Distribution
  • Patent use
  • Private use
Limitations
  • Trademark use
  • Liability
  • Warranty
Conditions
  • License and copyright notice
  • State changes
README.md 32 КБ
Копировать Редактировать Web IDE Исходные данные Просмотреть построчно История
gitlife-traslator Отправлено 24.11.2024 04:51 111eaec

Минимайс

Минимайс — это простая, но мощная система плагинов, подобная OSGi и основанная на NodeJS. Она разработана с использованием ES6 и интегрированной среды разработки VSCode.

let minima = new Minima(path.join(__dirname, 'plugins'));
minima.start();

Архитектура Минимайса показана ниже.

image

Система имеет три функции:

  • Динамический плагин: определение структуры плагина, конфигурации плагина, зависимостей плагина, жизненного цикла плагина и загрузки классов плагина;
  • Сервис: коммуникация между плагинами с помощью SOA;
  • Расширение: поддержка расширения для плагина.

Необходимые условия

  • Установлен NodeJS.
  • Требуется Babel.
$ npm install --g babel-cli
  • ESLint и JSHint не обязательны.
  • Интегрированная среда разработки — vscode, которая очень нравится автору.

Установка

Установите с помощью npm:

$ npm install --save minimajs

Использование

Minima — это контейнер системы плагинов. Необходимо создать экземпляр системы плагинов и запустить его.

image

import { Minima } from 'minimajs';
import path from 'path';

let minima = new Minima(path.join(__dirname, 'plugins'));
minima.start();

Примеры плагинов

Создайте простой плагин в каталоге plugins, как показано ниже.

Файл plugin.json в папке demoPlugin показан ниже. Здесь определяется logService.

{
    "id": "demoPlugin",
    "startLevel": 5,
    "version": "1.0.0",
    "services": [{
        "name": "logService",
        "service": "LogService.js"
    }]
}

Activator.js в папке demoPlugin показан ниже. Он обрабатывает extensionPoint «commands».

import { Minima, Extension, ExtensionAction, PluginContext, log } from 'minimajs';

export default class Activator {
    constructor() {
        this.start = this.start.bind(this);
        this.stop = this.stop.bind(this);

        this.handleCommandExtensions = this.handleCommandExtensions.bind(this);
        this.extensionChangedListener = this.extensionChangedListener.bind(this);
    }

    /**
     * 插件入口
     * 
     * @param {PluginContext} context 插件上下文
     * @memberof Activator
     */
    start(context) {
        context.addExtensionChangedListener(this.extensionChangedListener);
        this.handleCommandExtensions();
    }

    handleCommandExtensions() {
        let extensions = Minima.instance.getExtensions('commands');
        for (let extension of extensions) {
            let Command = extension.owner.loadClass(extension.data.command).default;
            let command = new Command();
            command.run();
        }

        log.logger.info(`The commands extension size is ${extensions.size}.`);
    }

    extensionChangedListener(extension, action) {
        this.handleCommandExtensions();
    }

    stop(context) {}
}

Затем создайте ещё один плагин с именем demoPlugin2, как показано ниже. demoPlugin2 будет использовать logService, зарегистрированный demoPlugin, и регистрировать расширение в extensionPoint «commands».

В EchoCommand demoPlugin2 загрузит класс из demoPlugin.

// 1 plugin.config
{
    "id": "demoPlugin2",
    "version": "1.0.0",
    "dependencies": [{
        "id": "demoPlugin",
        "version": "1.0.0"
    }],
    "extensions": [{
        "id": "commands",
        "data": {
            "name": "echo",
            "command": "commands/EchoCommand.js"
        }
    }]
}
// 2 Activator.js
import { PluginContext, log } from 'minimajs';

export default class Activator {
    static logService = null;

    constructor() {
        this.start = this.start.bind(this);
        this.stop = this.stop.bind(this);
    }

    /**
     * 插件入口
     * 
     * @param {PluginContext} context 插件上下контекст
     * @memberof Activator
     */
    start(context) {
        let logService = context.getDefaultService('logService');
        if (!logService) {
            throw new Error('The logService can not be null.');
        }
        Activator.logService = logService;

        logService.log('Get the logService successfully.');
    }

    stop(context) {}
}

После запуска... Текст запроса:

[2017-7-30 12:03:50.833] [INFO] log - Loading plugins from /Users/lorry/VSCodeProjects/minima-github/minimajs/example/build/plugins.
[2017-7-30 12:03:50.839] [INFO] log - Plugin demoPlugin is loaded from /Users/lorry/VSCodeProjects/minima-github/minimajs/example/build/plugins/demoPlugin.
[2017-7-30 12:03:50.840] [INFO] log - Plugin demoPlugin2 is loaded from /Users/lorry/VSCodeProjects/minima-github/minimajs/example/build/plugins/demoPlugin2.
[2017-7-30 12:03:50.840] [INFO] log - Plugins are loaded from /Users/lorry/VSCodeProjects/minima-github/minimajs/example/build/plugins completed.
[2017-7-30 12:03:50.841] [INFO] log - There are 2 plugins loaded.
[2017-7-30 12:03:50.845] [INFO] log - Starting the plugins with active initializedState.
[2017-7-30 12:03:50.846] [INFO] log - The plugin demoPlugin is starting.
[2017-7-30 12:03:50.929] [INFO] log - The commands extension size is 0.
[2017-7-30 12:03:50.954] [INFO] log - The plugin demoPlugin is active.
[2017-7-30 12:03:50.955] [INFO] log - The plugin demoPlugin2 is starting.
[2017-7-30 12:03:50.979] [INFO] console - Get the logService successfully.
[2017-7-30 12:03:51.033] [INFO] console - The echo command is executed.
[2017-7-30 12:03:51.034] [INFO] log - The commands extension size is 1.
[2017-7-30 12:03:51.034] [INFO] log - The plugin demoPlugin2 is active.
[2017-7-30 12:03:51.034] [INFO] log - The plugins with active initializedState are started.

Перевод текста на русский язык:

[2017–7–30 12:03:50.833] [INFO] log — Загрузка плагинов из /Users/lorry/VSCodeProjects/minima-github/minimajs/example/build/plugins.
[2017–7–30 12:03:50.839] [INFO] log — Плагин demoPlugin загружен из /Users/lorry/VSCodeProjects/minima-github/minimajs/example/build/plugins/demoPlugin.
[2017–7–30 12:03:50.840] [INFO] log — Плагин demoPlugin2 загружен из /Users/lorry/VSCodeProjects/minima-github/minimajs/example/build/plugins/demoPlugin2.
[2017–7–30 12:03:50.840] [INFO] log — Плагины загружены из /Users/lorry/VSCodeProjects/minima-github/minimajs/example/build/plugins, загрузка завершена.
[2017–7–30 12:03:50.841] [INFO] log — Загружено 2 плагина.
[2017–7–30 12:03:50.845] [INFO] log — Запуск плагинов с активным инициализированным состоянием.
[2017–7–30 12:03:50.846] [INFO] log — Начинается работа плагина demoPlugin.
[2017–7–30 12:03:50.929] [INFO] log — Размер расширения команд равен 0.
[2017–7–30 12:03:50.954] [INFO] log — Плагин demoPlugin активен.
[2017–7–30 12:03:50.955] [INFO] log — Начинается работа плагина demoPlugin2.
[2017–7–30 12:03:50.979] [INFO] console — Успешно получен доступ к службе logService.
[2017–7–30 12:03:51.033] [INFO] console — Выполнена команда echo.
[2017–7–30 12:03:51.034] [INFO] log — Размер расширения команд равен 1.
[2017–7–30 12:03:51.034] [INFO] log — Плагин demoPlugin2 активен.
[2017–7–30 12:03:51.034] [INFO] log — Запущены плагины с активным инициализированным состоянием. Текст запроса:

is Activator.js. This file is optional, thus, the plugin is started or stopped directly. The plugin may include other files also, such as HTML, CSS, and so on.

2 The plugin.json

Below is a fully plugin.json example.

{
    "id": "demoPlugin",
    "name": "demoPlugin",
    "description": "The demo plugin.",
    "version": "1.0.1",
    "startLevel": 5,
    "initializedState": "active",
    "activator": "PluginActivator.js",
    "stoppable": true,
    "dependencies": [{
        "id": "demoPlugin",
        "version": "1.0.0"
    }],
    "services": [{
        "name": "myService",
        "service": "MyService.js",
        "properties": {
            "vendor": "lorry"
        }
    }],
    "extensions": [{
        "id": "myExtension",
        "data": {
            "extensionData": "lorry"
        }
    }, {
        "id": "myExtension2",
        "data": {
            "extensionData": "lorry2"
        }
    }, {
        "id": "minima.menus",
        "data": [{
            "url": "view.js",
            "text": "view"
        }]
    }]
}

Перевод текста на русский язык:

Это файл Activator.js. Этот файл является необязательным, поэтому плагин запускается или останавливается напрямую. Плагин также может включать другие файлы, такие как HTML, CSS и так далее.

Ниже приведён полный пример файла plugin.json.

{
  "id": "demoPlugin",
  "name": "demoPlugin",
  "description": "Демонстрационный плагин.",
  "version": "1.0.1",
  "startLevel": 5,
  "initializedState": "active",
  "activator": "PluginActivator.js",
  "stoppable": true,
  "dependencies": [
    {
      "id": "demoPlugin",
      "version": "1.0.0"
    }
  ],
  "services": [
    {
      "name": "myService",
      "service": "MyService.js",
      "properties": {
        "vendor": "lorry"
      }
    }
  ],
  "extensions": [
    {
      "id": "myExtension",
      "data": {
        "extensionData": "lorry"
      }
    },
    {
      "id": "myExtension2",
      "data": {
        "extensionData": "lorry2"
      }
    },
    {
      "id": "minima.menus",
      "data": [
        {
          "url": "view.js",
          "text": "view"
        }
      ]
    }
  ]
}
``` **Атрибуты**

Идентификатор  это уникальный идентификатор ExtensionPoint, данные  это содержимое расширения, которое будет зарегистрировано в ExtensionPoint и может быть получено с помощью метода getExtensions класса Minima.Instance или PluginContext.getExtensions.

```json
[{
    "id": "myExtension",
    "data": {
        "extensionData": "lorry"
    }
}, {
    "id": "myExtension2",
    "data": {
        "extensionData": "lorry2"
    }
}, {
    "id": "minima.menus",
    "data": [{
        "url": "view.js",
        "text": "view"
    }]
}]

Атрибут data — это любое значение, определяемое плагином, который предоставляет ExtensionPoint. Атрибут data может быть строкой, массивом, объектом и т. д.

3. Activator

Activator предназначен для определения запуска и остановки. Каждый Activator содержит две функции с именами start и stop. Когда плагин запускается, вызывается функция start. Функция stop вызывается, когда плагин останавливается.

Activator является необязательным. Плагин может быть определён без Activator. Таким образом, он будет запускаться или останавливаться напрямую. Кроме того, файл Activator по умолчанию — Activator.js в каталоге плагина. Если вы определите Activator с другим именем файла, вам нужно указать атрибут activator в plugin.json.

Activator определяется следующим образом:

export default class Activator {
    constructor() {
        this.start = this.start.bind(this);
        this.stop = this.stop.bind(this);
    }

    start(context) {
        // TODO: do something when starting
    }

    stop(context) {
        // TODO: do something when stopping
    }
}

В каждой функции start и stop в Activator есть параметр с именем context. Это экземпляр PluginContext. Вы можете использовать PluginContext для доступа к функциональным возможностям фреймворка, таким как добавление или получение сервиса, получение расширений, получение плагинов, установка другого плагина и т.д.

Activator используется для инициализации ресурсов текущего плагина и освобождения их после остановки. Любое исключение, возникающее в функции start, блокирует запуск плагина, плагин останется в состоянии «разрешено». Но плагин всё равно остановится, если исключение произойдёт в методе stop.

4. PluginContext Class

PluginContext — это общий класс при определении плагина. Он предоставляет следующие функциональные возможности:

  • текущий плагин: для получения экземпляра текущего плагина; использование экземпляра плагина будет описано в следующем разделе.
  • сервис: для добавления и получения сервисов из фреймворка плагина.
  • расширение: для получения расширений из фреймворка плагина.
  • жизненный цикл плагина: для динамической установки плагина во фреймворк плагина.
  • событие: для прослушивания событий изменения сервиса, события изменения расширения, события изменения жизненного цикла плагина, событий фреймворка.
  • Вы можете получить более подробную информацию из ссылок на API.

5. Plugin Class

Плагин — ещё один общий класс при определении плагина. Он обеспечивает следующие функциональные возможности:

  • текущий плагин: чтобы получить информацию о текущем плагине, такую как каталог плагина, идентификатор, имя, версия и т. д.
  • жизненный цикл: для запуска, остановки, удаления текущего плагина.
  • загрузка класса: для загрузки модуля JS из текущего плагина.
  • Вы можете получить больше информации из ссылок на API.

6. Жизненный цикл

Фреймворк minimajs поддерживает установку, запуск, остановку и удаление во время выполнения. У каждого плагина есть установленные, разрешённые, запущенные, активные, останавливаемые, удалённые определения состояний.

Когда фреймворк устанавливает плагин, он читает файл plugin.json, проверяет plugin.json и создаёт экземпляр плагина. Если плагин установлен, его состояние — «установленное».

После установки плагина фреймворк немедленно разрешает его зависимости. Это означает, что плагин найдёт все зависимые плагины. Если зависимый плагин не существует или не может быть разрешён, плагин не может быть успешно разрешён, поэтому его состояние остаётся «установленным», в противном случае его состояние «разрешено». Как только плагин находится в состоянии «разрешён», это означает, что он готов к работе. Минимайз фреймворк: запуск, остановка и удаление плагина

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

  • Если текущий плагин активен, просто возвращается.
  • Если текущий плагин удалён, генерирует исключение.
  • Если уровень запуска плагина больше уровня запуска фреймворка, генерирует исключение.
  • Если не удаётся разрешить текущий плагин, генерирует исключение.
  • Изменяет состояние на «запуск».
  • Создаёт экземпляр PluginContext.
  • Загружает файл активатора, если он не определён, переходит к следующему шагу. В противном случае загружает модуль JS активатора, создаёт экземпляр и вызывает функцию start(context). Любое возникшее исключение останавливает запуск плагина.
  • Регистрирует сервисы текущего плагина, определённые в файле plugin.json, во фреймворке.
  • Регистрирует расширения текущего плагина, определённые в файле plugin.json, во фреймворке.
  • Изменяет состояние на «активное».
  • При любом исключении во время запуска состояние изменяется на «разрешено».
  • Любое состояние текущего плагина инициирует событие жизненного цикла плагина.

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

  • Если текущий плагин удалён, генерирует исключение.
  • Если состояние не «активно» или атрибут stoppable в plugin.json имеет значение false, генерирует исключение.
  • Изменяет состояние на «остановка».
  • Вызывает функцию stop(context) активатора, если она определена. Любые исключения игнорируются.
  • Отменяет регистрацию сервисов, определённых в файле plugin.json текущего плагина, во фреймворке.
  • Отменяет регистрацию расширений, определённых в файле plugin.json текущего плагина, во фреймворке.
  • Изменяет состояние на «разрешённое».
  • Любое состояние текущего плагина инициирует событие жизненного цикла плагина.

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

  • Останавливает его, а затем изменяет состояние на «удалено».
  • Можно выполнить любое действие жизненного цикла для удалённого плагина.

Как создать сервис

Сервис в минимайз фреймворке используется для взаимодействия между плагинами. Один плагин регистрирует сервис, другой плагин может использовать этот сервис. Сервис можно зарегистрировать и отменить регистрацию во время выполнения.

  1. Определение сервиса

Сервис предоставляет некоторые общие функции, такие как определение класса LogService, как показано ниже.

export default class LogService {
    log(message) {
        if (message) {
            console.log(message);
        }
    }
}
  1. Регистрация сервиса

Мы можем зарегистрировать сервис в файле plugin.json или экземпляре PluginContext функции start в активаторе.
Можно указать имя, путь к файлу сервиса относительно каталога плагина и свойства сервиса. Обратите внимание, что свойства сервиса используются для фильтрации сервисов, зарегистрированных с тем же именем сервиса.

{
    "id": "demoPlugin",
    "startLevel": 5,
    "version": "1.0.0",
    "services": [{
        "name": "logService",
        "service": "service/LogService.js", 
        "properties": {
            "vendor": "lorry"
        }
    }]
}  

Также мы можем зарегистрировать сервис в активаторе.

export default class Activator {
    constructor() {
        this.start = this.start.bind(this);
        this.stop = this.stop.bind(this);
    }

    start(context) {
        this.logServiceRegistry = context.addService('logService', new LogService());
    }

    stop(context) {
        context.removeService(this.logServiceRegistry); // This is Optional, it will be done by the minimajs framework when stopping.
    }
}

Удаление сервиса в функции stop необязательно, минимайз фреймворк удалит сервисы, зарегистрированные плагином, при остановке.

  1. Получение сервиса

Плагин может получить сервис с помощью PluginContext или Minima.instance.
Ниже показано использование PluginContext. Можно получить пустой сервис, если сервис не зарегистрирован или отменён, и необходимо убедиться, что сервис не равен нулю перед использованием сервиса.

export default class Activator {
    constructor() {
        this.start = this.start.bind(this);
        this.stop = this.stop.bind(this);
    }

    start(context) {
        let logService = context.getDefaultService('logService');
        // or let logService = **Контекст.getDefaultService('logService', {vendor: 'lorry'})**

Пусть logServices = контекст.getServices('logService');
// или пусть logServices = контекст.getServices('logservice', {vendor: 'lorry'});
}

stop(контекст) {
    
}
}

4 Event

Вы можете использовать PluginContext или Minima.instance для прослушивания события изменения сервиса. Например, ниже.

export default class Activator {
    static logService;

    constructor() {
        this.start = this.start.bind(this);
        this.stop = this.stop.bind(this);

        this.serviceChangedListener = this.serviceChangedListener.bind(this);
    }

    start(context) {
        Activator.logService = context.getDefaultService('logService');
        context.addServiceChangedListener
    }

    serviceChangedListener(name, action) {
        if (name === 'logService') {
            Activator.logService = context.getDefaultService('logService');
        }
    }

    stop(context) {
        
    }
}

Как создать расширение

Функция расширения предоставляет возможность плагину расширять функциональность другого плагина без изменения кода. Эта функция следует модели расширяемости ExtensionPoint-Extension. Расширение доступно при запуске плагина и удаляется после остановки.

1 Определите extensionPoint и обработайте его

Расширение, которое будет расширено во время выполнения, должно определить идентификатор extensionPoint. ExtensionPoint уникален. И плагин должен обрабатывать расширения, зарегистрированные другими плагинами.

import { Minima, Extension, ExtensionAction, PluginContext, log } from 'minimajs';

export default class Activator {
    constructor() {
        this.start = this.start.bind(this);
        this.stop = this.stop.bind(this);

        this.handleCommandExtensions = this.handleCommandExtensions.bind(this);
        this.extensionChangedListener = this.extensionChangedListener.bind(this);
    }

    /**
     * Плагин входа
     * 
     * @param {PluginContext} контекст Контекст плагина
     * Член Activator
     */
    start(контекст) {
        контекст.addExtensionChangedListener(this.extensionChangedListener);
        this.handleCommandExtensions();
    }

    handleCommandExtensions() {
        пусть расширения = Minima.instance.getExtensions('commands');
        для (пусть расширение из расширений) {
            пусть Command = расширение.владелец.loadClass(расширение.данные.команда).по умолчанию;
            пусть команда = новая команда();
            команда.запустить();
        }

        log.logger.info(`Размер расширения команд составляет ${extensions.size}.`);
    }

    extensionChangedListener(расширение, действие) {
        этот.handleCommandExtensions();
    }

    остановить (контекст) {}
}

2 Расширение

Плагин будет расширять функциональность другого плагина, он определит атрибут extensions плагина.json. Расширение и его содержимое должны соответствовать правилам ExtensionPoint.

Ниже приведён атрибут extensions файла plugin.json.

{
    "id": "demoPlugin2",
    "version": "1.0.0",
    "dependencies": [{
        "id": "demoPlugin",
        "version": "1.0.0"
    }],
    "extensions": [{
        "id": "commands",
        "data": {
            "name": "echo",
            "command": "commands/EchoCommand.js"
        }
    }]
}

Ниже приведено определение EchoCommand.js.

импорт {Minima} из 'minimajs';

экспорт по умолчанию класс EchoCommand {
    конструктор() {
        это.run = это.run.bind(это);
    }

    запустить() {
        пусть demoPlugin = Minima.instance.getPlugin('demoPlugin');
        пусть Assert = demoPlugin.loadClass('utilities/Assert.js').по умолчанию;
        Assert.notNull('demoPlugin', demoPlugin);

        console.log('Выполнена команда echo.');
    }
}

Расширение должно соответствовать требованиям ExtensionPoint.

3 Событие

Плагину, который может быть расширен другими плагинами, потребуется прослушивать событие изменения расширения и реагировать на него. Мы можем использовать PluginContext.addExtensionChangedListener или Minima.instance.addExtensionChangedListener для прослушивания события изменения расширения. ``` импорт { Minima, Extension, ExtensionAction, PluginContext, log } из 'minimajs';

экспорт default класс Activator { конструктор() { this.start = this.start.bind(this); this.stop = this.stop.bind(this);

    this.handleCommandExtensions = this.handleCommandExtensions.bind(this);
    this.extensionChangedListener = this.extensionChangedListener.bind(this);
}

/**
 * 插件入口
 *
 * @param {PluginContext} context 插件上下文
 * @memberof Activator
 */
старт(контекст) {
    контекст.addExtensionChangedListener(this.extensionChangedListener);
    this.handleCommandExtensions();
}

handleCommandExtensions() {
    let extensions = Minima.instance.getExtensions('commands');
    for (let extension of extensions) {
        let Command = extension.owner.loadClass(extension.data.command).default;
        let command = new Command();
        command.run();
    }

    log.logger.info(`Размер расширения команд: ${extensions.size}.`);
}

extensionChangedListener(расширение, действие) {
    this.handleCommandExtensions();
}

стоп(контекст) {}

}


**Как использовать журнал для поиска ошибок**

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

## О проекте

### Вклад

Для сообщений об ошибках и запросов функций, пожалуйста, свяжитесь со мной по адресу: 23171532@qq.com.

### Автор

Ларри Чен

Имеет 10-летний опыт работы с фреймворком плагинов. Эксперт в OSGi.

## Дискуссионная группа QQ

При возникновении проблем, пожалуйста, свяжитесь со мной через группу QQ, как показано ниже.
![image](https://github.com/lorry2018/minimajs/blob/master/docs/imgs/qqgroup.jpg)

## Лицензия

Apache License 2.0.

Опубликовать ( 0 )

Вы можете оставить комментарий после Вход в систему

1
https://api.gitlife.ru/oschina-mirror/lorrychen-minimajs.git
git@api.gitlife.ru:oschina-mirror/lorrychen-minimajs.git
oschina-mirror
lorrychen-minimajs
lorrychen-minimajs
master