Provides a lightweight plugin manager for Node / NPM & the browser with eventbus integration for plugins in a safe and protected manner across NPM modules, local files, and preloaded object instances. This pattern facilitates message passing between modules versus direct dependencies / method invocation.

A default eventbus will be created, but you may also pass in an eventbus from @typhonjs-plugin/eventbus and the plugin manager will register by default under these event categories:

plugins:async:add - PluginManager#add

plugins:async:add:all - PluginManager#addAll

plugins:async:destroy:manager - PluginManager#destroy

plugins:async:remove - PluginManager#remove

plugins:async:remove:all - PluginManager#removeAll

plugins:get:enabled - PluginManager#getEnabled

plugins:get:options - PluginManager#getOptions

plugins:get:plugin:by:event - PluginManager#getPluginByEvent

plugins:get:plugin:data - PluginManager#getPluginData

plugins:get:plugin:events - PluginManager#getPluginEvents

plugins:get:plugin:names - PluginManager#getPluginNames

plugins:has:plugin - PluginManager#hasPlugins

plugins:is:valid:config - PluginManager#isValidConfig

plugins:set:enabled - PluginManager#setEnabled

plugins:set:options - PluginManager#setOptions

Automatically when a plugin is loaded and unloaded respective functions onPluginLoad and onPluginUnload will be attempted to be invoked on the plugin. This is an opportunity for the plugin to receive any associated eventbus and wire itself into it. It should be noted that a protected proxy around the eventbus is passed to the plugins such that when the plugin is removed automatically all events registered on the eventbus are cleaned up without a plugin author needing to do this manually in the onPluginUnload callback. This solves any dangling event binding issues.

By supporting ES Modules / CommonJS in Node and ES Modules in the browser the plugin manager is by nature asynchronous for the core methods of adding / removing plugins and destroying the manager. The lifecycle methods onPluginLoad and onPluginUnload will be awaited on such that if a plugin returns a Promise or is an async method then it will complete before execution continues.

It is recommended to interact with the plugin manager eventbus through an eventbus proxy. The createEventbusProxy method will return a proxy to the default or currently set eventbus.

It should be noted that this module re-exports @typhonjs-plugin/eventbus which is available as named exports via the eventbus subpath export:

// Main Eventbus implementations:
import { Eventbus, EventbusProxy, EventbusSecure } from '#runtime/plugin/manager/eventbus';

// Consistent bus instances useful for testing and broad accessibility:
import { mainEventbus, pluginEventbus, testEventbus } from '#runtime/plugin/manager/eventbus/buses';

This reexport is for convenience as it provides one single distribution for Node & browser usage.

If external eventbus functionality is enabled by passing in an eventbus in the constructor of PluginManager it is important especially if using an existing process / global level eventbus instance from either this module or @typhonjs-plugin/eventbus to call PluginManager#destroy to clean up all plugin eventbus resources and the plugin manager event bindings; this is primarily a testing concern when running repeated tests over a reused eventbus.

For more information on Eventbus functionality please see:

https://www.npmjs.com/package/@typhonjs-plugin/eventbus

The PluginManager instance can be extended through runtime composition by passing in classes that implement PluginSupportImpl. One such implementation is available PluginInvokeSupport which enables directly invoking methods of all or specific plugins. Please see the documentation for PluginInvokeSupport for more details.

Several abbreviated examples follow. Please see the wiki for more details: TODO: add wiki link

import { PluginManager } from '@typhonjs-plugin/manager';

const pluginManager = new PluginManager();

await pluginManager.add({ name: 'an-npm-plugin-enabled-module' });
await pluginManager.add({ name: 'my-local-module', target: './myModule.js' });

const eventbus = pluginManager.createEventbusProxy();

// Let's say an-npm-plugin-enabled-module responds to 'cool:event' which returns 'true'.
// Let's say my-local-module responds to 'hot:event' which returns 'false'.
// Both of the plugin / modules will have 'onPluginLoaded' invoked with a proxy to the eventbus and any plugin
// options defined.

// One can then use the eventbus functionality to invoke associated module / plugin methods even retrieving results.
assert(eventbus.triggerSync('cool:event') === true);
assert(eventbus.triggerSync('hot:event') === false);

Constructors

Accessors

  • get isDestroyed(): boolean
  • Returns whether this plugin manager has been destroyed.

    Returns boolean

    Returns whether this plugin manager has been destroyed.

Methods

  • Adds a plugin by the given configuration parameters. A plugin name is always required. If no other options are provided then the name doubles as the NPM module / local file to load. The loading first checks for an existing instance to use as the plugin. Then the target is chosen as the NPM module / local file to load. By passing in options this will be stored and accessible to the plugin during all callbacks.

    Parameters

    • pluginConfig: PluginConfig

      Defines the plugin to load.

    • OptionalmoduleData: object

      Optional object hash to associate with plugin.

    Returns Promise<PluginData>

    The PluginData that represents the plugin added.

  • Initializes multiple plugins in a single call.

    Parameters

    • pluginConfigs: Iterable<PluginConfig, any, any>

      An iterable list of plugin config object hash entries.

    • OptionalmoduleData: object

      Optional object hash to associate with all plugins.

    Returns Promise<PluginData[]>

    An array of PluginData objects of all added plugins.

  • If an eventbus is assigned to this plugin manager then a new EventbusProxy wrapping this eventbus is returned. It is added to this.#eventbusProxies so †hat the instances are destroyed when the plugin manager is destroyed.

    Returns EventbusProxy

    A proxy for the currently set Eventbus.

  • If an eventbus is assigned to this plugin manager then a new EventbusSecure wrapping this eventbus is returned. It is added to this.#eventbusSecure so †hat the instances are destroyed when the plugin manager is destroyed.

    Parameters

    • Optionalname: string

      Optional name for the EventbusSecure instance.

    Returns EventbusSecure

    A secure wrapper for the currently set Eventbus.

  • Returns the enabled state of a plugin, a list of plugins, or all plugins.

    Parameters

    • Optionalopts: {
          plugins?: string | Iterable<string, any, any>;
      }

      Options object. If undefined all plugin enabled state is returned.

      • Optionalplugins?: string | Iterable<string, any, any>

        Plugin name or iterable list of names to get state.

    Returns boolean | DataOutPluginEnabled[]

    Enabled state for single plugin or array of results for multiple plugins.

  • Returns any associated eventbus.

    Returns Eventbus

    The associated eventbus.

  • Returns the event binding names registered on any associated plugin EventbusProxy.

    Parameters

    • opts: {
          event: string | RegExp;
      }

      Options object.

      • event: string | RegExp

        Event name or RegExp to match event names.

    Returns string[] | DataOutPluginEvents[]

    Event binding names registered from the plugin.

  • Gets the plugin data for a plugin, list of plugins, or all plugins.

    Parameters

    • Optionalopts: {
          plugins?: string | Iterable<string, any, any>;
      }

      Options object. If undefined all plugin data is returned.

      • Optionalplugins?: string | Iterable<string, any, any>

        Plugin name or iterable list of names to get plugin data.

    Returns PluginData | PluginData[]

    The plugin data for a plugin or list of plugins.

  • Gets a PluginEntry instance for the given plugin name. This method is primarily for PluginSupportImpl classes.

    Parameters

    • plugin: string

      The plugin name to get.

    Returns PluginEntry

    The PluginEntry for the given plugin name.

  • Returns the event binding names registered on any associated plugin EventbusProxy.

    Parameters

    • Optionalopts: {
          plugins?: string | Iterable<string, any, any>;
      }

      Options object. If undefined all plugin data is returned.

      • Optionalplugins?: string | Iterable<string, any, any>

        Plugin name or iterable list of names to get plugin data.

    Returns DataOutPluginEvents[]

    Event binding names registered from the plugin.

  • Returns an iterable of plugin map keys (plugin names). This method is primarily for PluginSupportImpl classes.

    Returns Iterable<string, any, any>

    An iterable of plugin map keys.

  • Returns an iterable of plugin map keys (plugin names). This method is primarily for PluginSupportImpl classes.

    Returns Iterable<PluginEntry, any, any>

    An iterable of plugin map keys.

  • Returns all plugin names or if enabled is set then return plugins matching the enabled state.

    Parameters

    • Optionalopts: {
          enabled?: boolean;
      }

      Options object. If undefined all plugin names are returned regardless of enabled state.

      • Optionalenabled?: boolean

        If enabled is a boolean it will return plugins given their enabled state.

    Returns string[]

    A list of plugin names optionally by enabled state.

  • Returns true if there is a plugin loaded with the given plugin name(s). If no options are provided then the result will be if any plugins are loaded.

    Parameters

    • Optionalopts: {
          plugins?: string | Iterable<string, any, any>;
      }

      Options object. If undefined returns whether there are any plugins.

      • Optionalplugins?: string | Iterable<string, any, any>

        Plugin name or iterable list of names to check existence.

    Returns boolean

    True if given plugin(s) exist.

  • Performs validation of a PluginConfig.

    Parameters

    Returns boolean

    True if the given PluginConfig is valid.

  • Unloads / reloads the plugin invoking onPluginUnload / then onPluginReload

    Parameters

    • opts: {
          instance?: object;
          plugin: string;
          silent?: boolean;
      }

      Options object.

      • Optionalinstance?: object

        Optional instance to replace.

      • plugin: string

        Plugin name to reload.

      • Optionalsilent?: boolean

        Does not trigger any reload notification on the eventbus.

    Returns Promise<boolean>

    Result of reload attempt.

  • Removes a plugin by name or all names in an iterable list unloading them and clearing any event bindings automatically.

    Parameters

    • opts: {
          plugins: string | Iterable<string, any, any>;
      }

      Options object.

      • plugins: string | Iterable<string, any, any>

        Plugin name or iterable list of names to remove.

    Returns Promise<DataOutPluginRemoved[]>

    A list of plugin names and removal success state.

  • Sets the enabled state of a plugin, a list of plugins, or all plugins.

    Parameters

    • opts: {
          enabled: boolean;
          plugins?: string | Iterable<string, any, any>;
      }

      Options object.

      • enabled: boolean

        The enabled state.

      • Optionalplugins?: string | Iterable<string, any, any>

        Plugin name or iterable list of names to set state.

    Returns void

  • Sets the eventbus associated with this plugin manager. If any previous eventbus was associated all plugin manager events will be removed then added to the new eventbus. If there are any existing plugins being managed their events will be removed from the old eventbus and then onPluginLoad will be called with the new eventbus.

    Parameters

    • opts: {
          eventbus: Eventbus;
          eventPrepend?: string;
      }

      An options object.

      • eventbus: Eventbus

        The new eventbus to associate.

      • OptionaleventPrepend?: string

        An optional string to prepend to all of the event binding targets.

    Returns Promise<void>

  • Set optional parameters.

    Parameters

    Returns void