npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

app-plugins

v1.0.0

Published

Application plugin framework for Node.js and the browser

Downloads

9

Readme

Application Plugins

Node.js application plugin framework. If you want your application to be extensible and loosely coupled then this is the way to go.

Have you ever needed to write a Node.js application that is extensible? Maybe you

  • needed to enable a third party (like contractors) to write code for you without messing around in the main application
  • wanted to decouple the work of different teams
  • simply needed your codebase to be smaller and more manageable

then this is for you!

About

This module manages the plugins in memory by exposing a PluginManager and ServiceContainer.

The PluginManager interacts with the loaded plugin code, calling load and unload methods to manage the lifecycle and making sure that services are isolated between plugins and the main application so plugins can be unloaded at all times.

The plugin isolation means, that there are always multiple service instances.

  • one global instance on the plugin manager
  • one instance per plugin

Each instance gets created on first use so not all of those instances are necessarily alive in any given application state.

Having multiple instances allows us to separate plugins cleanly but comes with an extra challenge. When service calls are invoked, they must also check all other service instances. Consider this example of a routing service:

  • each plugin registers a route
  • when the application code tries to check whether a route is available, it has to check all the service instances since each plugin has registered its route on its own instance of the routing service
  • the routing service gets a list of all routing service instances
  • it needs to expose a method to communicate with the other instances, in this case to return the registered routes or to check only itself whether a route is available
  • once the service instance is found that can handle the request, the loop can be stopped

A function getServices is exposed on the Service base class and helps in managing the other service instances.

Code example:

class RoutingService extends Service {
  registerRoute(route: any): void {
    ...
  }
  
  canHandleRequest(request): boolean {
    return ...
  }
  
  handleRequest(request: Request) {
    if (this.canHandleRequest(request)) {
      // actually handle the route
      return ...
    }

    // check all service instances which one can handle the route
    const serviceList: List<RoutingService> = super.getServices();
    const routingService = serviceList.find(service => service.canHandleRequest(request);

    return routingService && routingService.handleRequest(request);
  }
}

Usage

Create a new instance of the PluginManager. This should be a singleton and manages all plugins in your application. Loading a plugin is a 2-stage process.

  • create an instance of Plugin passing the name of your plugin (filename or other unique identifier)

  • stage the plugin with the PluginManager calling pluginManager.stage(plugin), this will prepare the ServiceContainer instance specific for the plugin ** the main reason for this early process is to already give you access to the plugin's service instances before the plugin code has necessarily been loaded ** this can be used to hook into the Node.js module loading process and supply registered services through the "require" mechanic in Node

  • load the plugin by calling PluginManager.load(plugin, pluginModule)

    import { PluginManager, Plugin } from 'app-plugins';

    // create a new PluginManager instance and store it as a singleton in your application const pluginManager = new PluginManager(); pluginManager.registerService('SVC_LOGGER', LogService);

    // plugins need to be wrapped in the Plugin class before being staged in the PluginManager const plugin = new Plugin('test-plugin'); pluginManager.stage(plugin);

    // the Plugin class exposes the plugin specific service container in case specific services need to be registered for a particular plugin const log = plugin.getService('SVC_LOGGER');

    // the PluginManager will call TestPlugin.load const testPlugin = new TestPlugin(); await pluginManager.load(plugin, testPlugin);

    // unload the plugin if it is no longer required await pluginManager.unload(plugin);