Skip to content

Разработка плагина

В данном руководстве рассмотрим основы разработки плагина Runium.

Создадим плагин some-plugin, который:

  • будет загружаться Runium
  • добавит новый макрос
  • добавит хуки проекта

В каком виде существует плагин

Runium умеет загружать плагины двумя способами: как npm-пакеты и как отдельные файлы. Контракт у них одинаковый - меняется только способ доставки модуля.

npm-пакет

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

package.json сообщает Node.js формат модуля и указывает точку входа через main. Сначала пакет устанавливается в то же окружение, где установлен Runium, а затем добавляется по имени:

sh
npm install runium-some-plugin
runium plugin add runium-some-plugin

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

Отдельный файл

Для небольшого локального расширения не обязательно создавать и публиковать пакет. Плагин можно поместить в один файл и подключить напрямую:

sh
runium plugin add --file /absolute/path/to/runium-some-plugin.mjs

Такой файл должен иметь расширение .mjs. Runium загружает плагины как ES-модули, а Node.js определяет формат файла по расширению и ближайшему package.json. Для .js результат зависит от значения "type": вне npm-пакета файл может быть ошибочно воспринят как CommonJS. Расширение .mjs однозначно обозначает ES-модуль независимо от каталога и окружающих package.json, поэтому экспорт default будет интерпретирован предсказуемо.

TIP

В этом руководстве создаем npm-пакет: при таком подходе удобнее разделять функционал на несколько файлов и использовать зависимости. При необходимости его собранную точку входа можно распространять отдельно как .mjs.

Подготовка проекта

Для разработки плагина рекомендуется использовать TypeScript и пакет @runium/types-plugin.

TIP

Также описание типов доступно в справочнике Plugin и справочнике глобального объекта runium. Это может полезно при разработке на чистом JavaScript.

Начнем с отдельного npm-пакета:

sh
mkdir runium-some-plugin
cd runium-some-plugin
npm init -y
npm install --save-dev @runium/types-plugin typescript @types/node

Приведите package.json к следующему виду:

json
{
  "name": "runium-some-plugin",
  "version": "1.0.0",
  "type": "module",
  "main": "dist/index.js",
  "scripts": {
    "build": "tsc"
  },
  "keywords": ["runium", "runium-plugin"],
  "devDependencies": {
    "@runium/types-plugin": "latest",
    "@types/node": "latest",
    "typescript": "latest"
  }
}

А рядом создайте tsconfig.json:

json
{
  "compilerOptions": {
    "target": "ESNext",
    "module": "ESNext",
    "rootDir": "src",
    "outDir": "dist",
    "strict": true,
    "skipLibCheck": true,
    "types": ["node", "@runium/types-plugin"]
  },
  "include": ["src/**/*.ts"]
}

Создайте каталог src.

Теперь TypeScript знает о глобальном объекте runium, исходники находятся в src, а готовый ESM-модуль появится в dist.

Шаг 1. Оживляем плагин

Реализуем минимальный модуль, который Runium сможет загрузить и распознать.

Создайте src/index.ts. Плагин экспортирует синхронную фабрику: Runium вызовет ее при старте и получит описание плагин.

ts
import type { Plugin } from '@runium/types-plugin';

export default function (): Plugin {
  return {
    name: 'some-plugin',
  };
}

TIP

Подробнее о свойствах возвращаемого объекта можно узнать справочнике.

Пока единственная возможность плагина - сообщить свое имя. Этого уже достаточно, чтобы проверить всю цепочку от TypeScript до Runium:

sh
npm run build
runium plugin add --file ./dist/index.js
runium plugin list

Результат: some-plugin появился в списке плагинов. У нас есть маленькая, но рабочая основа, которую можно развивать.

Шаг 2. Добавляем макрос

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

Макрос принимает строки и возвращает строку. Добавим макрос $greet(name), который возвращает приветствие для переданного имени.

ts
import type { Plugin } from '@runium/types-plugin';

export default function (): Plugin {
  return {
    name: 'some-plugin',
    project: {
      macros: {
        greet(name: string): string {
          return `Hello, ${name}!`;
        },
      },
    },
  };
}

Используем новый макрос в проекте:

json
{
  "id": "example",
  "tasks": [
    {
      "id": "welcome",
      "options": {
        "command": "echo",
        "arguments": ["$greet(Runium)"]
      }
    }
  ]
}

Результат: перед запуском конфигурации Runium заменяет $greet(Runium) на Hello, Runium!.

Шаг 3. Подключаем хуки проекта

Добавим хуки проекта.

ts
import type { Plugin } from '@runium/types-plugin';

export default function (): Plugin {
  return {
    name: 'some-plugin',
    hooks: {
      project: {
        async beforeConfigRead(path) {
          runium.output.log('Reading config from:', path);
          // здесь знаем, какой файл конфигурации будет прочитан
        },
        async afterConfigRead(content) {
          runium.output.log('Config read:', content);
          // здесь получаем содержимое файла конфигурации
          // можем преобразовать его (например, преобразовать формат из YAML в JSON)
          return content;
        },
        async afterConfigParse(config) {
          runium.output.log('Parsed config:', config);
          // здесь получаем объект конфигурации
          // можем преобразовать его (например, изменить или удалить свойства)
          return config;
        },
        async beforeStart({ name }) {
          // здесь проект готов к запуску
          // можем, например, подписаться на события изменения состояния задач
          runium.output.log('Starting project:', name ?? 'unnamed');
        },
      },
    },
    project: {
      macros: {
        greet(name: string): string {
          return `Hello, ${name}!`;
        },
      },
    },
  };
}

Запустите любой проект Runium, runium project start, чтобы проверить вызов хуков на каждом этапе.

Результат: плагин теперь участвует в жизненном цикле проекта.

Что дальше?

  • Справочник по плагину - полный список свойств и методов, которые может возвращать плагин: хуки, макросы, задачи, действия, триггеры и расширение схемы.
  • Глобальный объект runium - описание API, доступного плагину во время выполнения: работа с профилем, вводом-выводом, параметрами запуска и другими возможностями.
  • Исходный код официальных плагинов на GitHub или GitVerse - здесь можно найти примеры регистрации команд, триггеров, новых типов задач и пр.