Skip to main content

Extending Functionality

Introduction to Aetheria's plugin system

Aetheria's plugin system differs from in its approach to extension depending on the type of plugin. There are two types of plugins:

  • Backend plugins: are plugins that may be shipped with Aetheria and are specific to the backend. These plugins are loaded by the backend at runtime and they are not exposed to the frontend.
    The simplest backend plugin is a NestJS module that is dynamically registered but plugins may become more complex and provide almost unlimited functionalities.
  • Frontend plugins: Frontend plugins are plugins that are loaded by the frontend at runtime and are exposed to the user in the UI or using other methodologies.
    The simplest frontend plugins is a Next.js library exporting React components that are registered in the IOC container and already used or setup in the base installation.
    Plugins may become far more complex and also register new routes and pages in the admin panel or other locations.

Installing and activating plugins

Whatever the type of plugin, they are all installed and activated in the same way. Plugins are installed via the cli shipped in both the backend and frontend packages.

# local installation
nest start cli plugin install -n <plugin-name> -r <plugin-resolution-path>

# npm installation
nest start cli plugin install -n <plugin-name> -N

# tarball installation
nest start cli plugin install -n <plugin-name> -r <tarball-plugin-path> -t
FAQ

Is there a way to install plugins without using the cli?

Yes, there is.

The cli is just a wrapper around a series of configuration tweaks that are required to install a plugin. Even though you can manually install plugins it is strongly discouraged to do so as the cli will take care of all the required steps for you without the risk of forgetting something.

Which is the difference between local, npm and tarball installations?

As you may have noticed, there are three different ways to install a plugin. The difference between them is the way the plugin is resolved and installed.

As of v1.0.x ships with tree resolution strategies:

  • local: the plugin is resolved from the local filesystem. This is the default strategy.
  • npm: the plugin is resolved from the npm registry.
  • tarball: the plugin is resolved from a tarball file.
caution

Do not rely on the tarball nor on the npm strategy until the publishing of the official APM as they are not yet supported because of security concerns.

How do I know which strategy to use?

As of v1.0.x the only supported strategy is the local one. The npm and tarball strategies are not yet supported because of security concerns.

As of the release of the official APM, the shipped plugin manager will choose the correct strategy for you based on the plugin and data available.

Activating plugins

As of v1.0.x installed plugins are always activated. In order to disable a plugin you have to uninstall it.

caution

As of v1.1.x this behaviour will change and plugins will be installed and activated by default but they can be disabled without the need to uninstall them.

Creating a plugin

Plugins differs in their structure depending on the type of plugin, but they all share the same basic requirements.

Each plugin must have a package.json file with the following minimal structure:

package.json
{
"name": "plugin-name",
"version": "1.0.0",
// optional fields
"description": "A short description of the plugin",
"authors": [
{
"name": "John Doe",
"email": "[email protected]"
}
]
}

Other fields such as description and authors may be present but they are not required.

Backend plugins are NestJS modules that are dynamically registered at runtime. Anyway, the standard NestJS module structure is not enough for a plugin to be loaded by the backend.

Plugin types

All plugins in order to be loaded by the backend must be CommonJS plugins as Nest does not support yet ESM modules. Ensure you're using the correct plugin type by setting "type": "commonjs" inside your package.json.

A standard NestJS library module looks like this:

Standard NestJS library module structure
Standard NestJS library module structure

If generated via the nest CLI usually the index.ts inside the src folder is not created. This structure is anyway not enough, even if the index.ts file inside the src folder is created.

This is because in order to be automatically loaded at startup the plugin must export a default entrypoint from the root of the library module. This means that an additional index.ts file must be created in the root of the library module, aside the src folder.

A sample root index.ts file may look like this:

Root index.ts
// Import the module from the src folder and export it as default entrypoint
import { PluginExampleModule } from "./src";

export default PluginExampleModule;

// Optionally (but suggested) also re-export all the modules and utilities from the src folder
// in order to enhance the developer experience
export * from "./src";
info

In our example we've created and index.ts file inside the src folder that acts as an entrypoint for the whole directory, this is not a requirement and you can easily import single files as you'd normally do.

Depending on your setup your tsconfig.json file may need to be tweaked in order to allow the compiler to resolve the src folder and the root index.ts as a whole. The simplest way to do so is to add the following lines aside the compilerOptions object:

Partial of tsconfig.json
{
"include": [
"**/*"
]
}

If you've created your library module using the nest CLI you are already good to go, all its left to do is to build the plugin and install it.

info

All plugins must be built before being installed as they are not automatically built by the plugin manager. An un-built plugin will not be loaded by the backend.

An utility cli command is provided to build all plugins, inside the libs folder of the backend project you can run it via npm run build:plugins.