Build your own Plugin System Architecture

Build your own Plugin System Architecture

An ultimate reference guide if you are building your own plugin system architecture.

What is a plugin architecture?

For building modular, customizable, and easily extensible applications one of the common design pattern followed is plugin system or modular architecture. It allows one to add more features and components to the application without affecting the existing functionalities or core of the application.

Why build a plugin architecture?

In a tech world that evolves at the speed of light, keeping up is the latest technology is a bit difficult and switching to the latest tech stacks for all the projects is more difficult. We were facing the similar issue at GeekyAnts. Most of the projects used Prisma as the ORM, but now we wanted to move to Drizzle, doing this transition for all the large scale application caused a lot of trouble. Keeping these issue in mind we decided to build a pluggable fullstack javascript framework (gluestack-framework) that will manage all these integrations under the hood and provides its users with a consistent API.

Plugin Architecture

Let's discuss about how a plugin system; architecture looks like. A plugin system architecture has two parts:

  • Core Plugin

  • Supported Plugins

The core plugin provides the foundation on which developers can build their apps and the general business logic or bare minimum for the application to function. The foundation incase of gluestack-framework included initial folder structure, a local CLI setup that helps in plugin management and easy bootstrapping, and provided a communication link between various other plugins.

The other supported plugins can be considered as different modules which provides different functionalities and work independent of each other. All these plugins are dependent on core plugin and follow a certain guidelines and structure. These plugins can be removed and plugged anytime according to the requirement of the application.

Now that we have an idea about plugin architecture, let's deep dive into how we built plugin system architecture for gluestack-framework.

Building a Plugin System Architecture

Let's discuss about different points to keep in mind while building a plugin system.

  • The process of adding and removing plugins should be simple.

  • A plugin can have multiple instances.

  • Plugins should be able to communicate between themselves.

  • Plugins should be extensible.

  • Handling dependencies conflicts between plugins.

  • Storing the current state of project.

Let's have a look at each point in detail:

  1. Installation and management of different plugins must be an easy process. For this, we build a node glue cli in the core plugin that manages the installation and removal of different plugins. The CLI handles all these functionalities and provides with a simple interface to manage your app.

  2. The core plugin basically exports a BasePlugin class which is extended by all the plugins and the base class includes the common methods like build, watch etc. Each plugin can be considered as a class and a class can have multiple instances which we called pluginInstance. Each pluginInstance can be considered as a individual module. This is helpful incase of ERP application a user might need a website for their customers and one website for the administration, so a user can have two instances of web plugin named customer and admin. These websites will be independent of each other but still can access the same backend and database services.

  3. The communication between the two plugins happens through the core plugin. The core plugins maintains a global store where we save information regarding the plugins and their metadata. This is basically a singleton class which maintains a map of all the plugin classes. So, to access one plugin from another plugin we just need to call the getPluginByName method of AppCLI class.

 // AppCLI class exported from Core plugin
 class AppCLI{
      plugins: Array<IPlugin>;
    constructor() {
         this.plugins = [];
     }
    getPluginByName(pluginName: string) {
         for (const plugin of this.plugins) {
             if (plugin.getName() === pluginName) {
                 return plugin;
             }
         }
         return null;
     }
 }
// Other plugins extends BaseGluestackPlugin which exports app 
export class GluestackPlugin extends BaseGluestackPlugin{
   someRandomFunction(){
      const plugin = this.app.getPluginByName("web")
   }
}
  1. Plugins should be extensible i.e users must be able to create their own custom plugins by following a certain rules and guidelines and the created plugins must work seamlessly with the plugin system. To achieve this in gluestack-framework we created a BaseGluestackPlugin class which provides base functions and user can override them according to the functionality that plugin wants to provide.

  2. Another issue that was faced while building plugin system architecture was managing dependencies conflicts. As we know that all the plugins are dependent on core plugin and there are cases where one plugin is dependent on other plugin as well. Moreover, if two or more plugins uses typescript as a dependency, there is a chance that version of typescript for both the plugins might be different. For that using a monorepo was a good choice and this solved the issue of plugin dependencies as well. Using monorepo shared libraries or utilities can be versioned and updated consistently.

  3. Plugin system architecture gives us the modular system, each plugin provides a particular functionality/component and works independently. So it is important to store the current state of the application and store what plugins are currently installed and their metadata as well. For that, we were maintaining a .glue folder which contained the information about currently installed plugins and their paths.

    These are just some pointers that I shared above and are applicable to a larger set of things which I came across while building gluestack-framework. To know more about how we built a fullstack javascript framework, refer this link.