Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

A flexible and extensible TypeScript/JavaScript plugin system supporting dependency management, lifecycle control, service registration, and event communication.

Notifications You must be signed in to change notification settings

lenqwang/plugin-system

Repository files navigation

Plugin System

A flexible and extensible TypeScript/JavaScript plugin system supporting dependency management, lifecycle control, service registration, and event communication.

Features

  • 🔌 Plugin Lifecycle Management - Complete loading, activation, deactivation, and unloading workflow
  • 📦 Dependency Management - Automatic handling of plugin dependencies and loading order
  • 🎯 Service Registration - Plugins can register and use shared services
  • 📡 Event System - EventEmitter-based inter-plugin communication
  • ⚙️ Configuration Management - Dynamic configuration updates and hot reloading
  • 🏷️ Tag Classification - Organize and find plugins by tags
  • 🔍 Plugin Discovery - Automatic plugin discovery and loading
  • 📊 Status Monitoring - Real-time plugin status and statistics monitoring
  • 🌐 Browser Support - Complete browser environment support with DOM and storage plugins
  • 📱 Cross-Platform - Supports both Node.js and browser environments

Architecture

The plugin system is designed with a clean separation between core functionality and platform-specific implementations:

src/
├── core/ # Platform-agnostic core functionality
│ ├── types.ts # Core interfaces and types
│ ├── base-plugin.ts # Abstract base plugin class
│ ├── plugin-manager.ts # Core plugin manager
│ ├── plugin-registry.ts # Plugin registration and discovery
│ └── plugin-loader.ts # Plugin loading utilities
├── platforms/
│ ├── node/ # Node.js-specific implementations
│ │ ├── index.ts # Node.js platform entry point
│ │ └── plugins/ # Node.js-specific plugins
│ │ ├── logger-plugin.ts
│ │ └── cache-plugin.ts
│ └── browser/ # Browser-specific implementations
│ ├── index.ts # Browser platform entry point
│ ├── event-emitter.ts # Browser-compatible EventEmitter
│ ├── plugin-manager.ts # Browser plugin manager
│ ├── base-plugin.ts # Browser base plugin class
│ └── plugins/ # Browser-specific plugins
│ ├── dom-plugin.ts
│ └── storage-plugin.ts
└── index.ts # Main entry point (Node.js)

Installation

npm install plugin-system

Quick Start

Node.js Environment

import { PluginManager, Logger, BasePlugin } from "plugin-system";
// Create a simple logger
class ConsoleLogger implements Logger {
 debug(message: string, ...args: any[]): void {
 console.debug(`[DEBUG] ${message}`, ...args);
 }
 info(message: string, ...args: any[]): void {
 console.info(`[INFO] ${message}`, ...args);
 }
 warn(message: string, ...args: any[]): void {
 console.warn(`[WARN] ${message}`, ...args);
 }
 error(message: string, ...args: any[]): void {
 console.error(`[ERROR] ${message}`, ...args);
 }
}
// Create a simple plugin
class MyPlugin extends BasePlugin {
 constructor() {
 super({
 name: "my-plugin",
 version: "1.0.0",
 description: "My custom plugin",
 author: "Your Name",
 tags: ["custom", "example"],
 priority: 50,
 });
 }
 protected async onInitialize(): Promise<void> {
 // Plugin initialization logic
 this.context.logger.info("Plugin initialized");
 // Register service
 this.context.services.register("myService", {
 doSomething: () => console.log("Doing something"),
 });
 }
 protected async onActivate(): Promise<void> {
 // Plugin activation logic
 this.context.logger.info("Plugin activated");
 }
 protected async onDeactivate(): Promise<void> {
 // Plugin deactivation logic
 this.context.logger.info("Plugin deactivated");
 }
 protected async onDispose(): Promise<void> {
 // Plugin cleanup logic
 this.context.services.unregister("myService");
 this.context.logger.info("Plugin disposed");
 }
}
// Use the plugin system
async function main() {
 const logger = new ConsoleLogger();
 const pluginManager = new PluginManager(logger);
 const myPlugin = new MyPlugin();
 await pluginManager.registerPlugin(myPlugin, {
 customOption: "value",
 });
 await pluginManager.activatePlugin("my-plugin");
 // Use plugin service
 const plugin = pluginManager.getPlugin("my-plugin") as any;
 const myService = plugin?.context?.services.get("myService");
 myService?.doSomething();
}
main().catch(console.error);

Browser Environment

<!DOCTYPE html>
<html>
 <head>
 <title>Plugin System Browser Example</title>
 </head>
 <body>
 <script src="dist/browser/plugin-system.umd.js"></script>
 <script>
 async function init() {
 // Create browser plugin system
 const pluginSystem = PluginSystem.createBrowserPluginSystem();
 // Initialize with default plugins (DOM and Storage)
 await pluginSystem.initializeWithDefaults();
 await pluginSystem.pluginManager.activateAll();
 // Use DOM plugin
 const domService = pluginSystem.pluginManager.getService("dom");
 const element = domService.createElement(
 "div",
 {
 style: "color: blue; padding: 10px;",
 },
 "Hello Plugin System!"
 );
 document.body.appendChild(element);
 }
 init().catch(console.error);
 </script>
 </body>
</html>

Built-in Plugins

LoggerPlugin - Advanced Logging

Provides advanced logging management with level control and file output.

import { LoggerPlugin } from "plugin-system";
const loggerPlugin = new LoggerPlugin();
await pluginManager.registerPlugin(loggerPlugin, {
 logLevel: "debug", // Log levels: debug, info, warn, error
 logFile: "./app.log", // Log file path (optional)
});

CachePlugin - Memory Cache

Provides in-memory caching service with TTL, LRU eviction, and memory management.

import { CachePlugin } from "plugin-system";
const cachePlugin = new CachePlugin();
await pluginManager.registerPlugin(cachePlugin, {
 maxSize: 1000, // Maximum cache entries
 ttl: 300000, // Default TTL (milliseconds)
});
// Use cache service
const cacheService = pluginManager
 .getPlugin("cache")
 ?.context?.services.get("cache");
cacheService.set("key", "value");
const value = cacheService.get("key");

Advanced Features

Dependency Management

Plugins can declare dependencies, and the system will automatically load them in the correct order:

export class AdvancedPlugin extends BasePlugin {
 constructor() {
 super({
 name: "advanced-plugin",
 version: "1.0.0",
 dependencies: ["logger", "cache"], // Depends on other plugins
 // ...
 });
 }
 protected async onDependencyStatusChange(
 dependency: string,
 status: PluginStatus
 ): Promise<void> {
 // Handle dependency status changes
 this.context.logger.info(`Dependency ${dependency} status changed to: ${status}`);
 }
}

Event Communication

Plugins can communicate through events:

// Send events
this.emit("custom-event", { data: "some data" });
// Listen for events
this.on("system:log", (data) => {
 console.log("Received log event:", data);
});
// Listen for other plugin events
pluginManager.on("plugin:other-plugin:some-event", (data) => {
 console.log("Received other plugin event:", data);
});

Hot Configuration Updates

Support for runtime plugin configuration updates:

// Update configuration
await pluginManager.updatePluginConfig('my-plugin', {
 newOption: 'new value'
});
// Handle configuration updates in plugin
protected async onConfigUpdate(config: PluginConfig): Promise<void> {
 // Handle configuration changes
 this.someOption = config.newOption;
}

Batch Operations

// Batch load all plugins (in dependency order)
await pluginManager.loadAll();
// Batch activate all plugins
await pluginManager.activateAll();
// Batch deactivate all plugins
await pluginManager.deactivateAll();
// Get active plugin list
const activePlugins = pluginManager.getActivePlugins();

Plugin Registry

Use plugin registry for advanced querying and management:

import { PluginRegistry } from "plugin-system";
const registry = new PluginRegistry();
// Find plugins by tag
const logPlugins = registry.getByTag("logging");
// Sort by priority
const sortedPlugins = registry.getByPriority();
// Search plugins
const results = registry.search({
 name: "cache",
 tags: ["performance"],
 author: "System",
});
// Get statistics
const stats = registry.getStats();

Plugin Discovery and Loading

Automatic plugin discovery and loading:

import {
 DefaultPluginLoader,
 DefaultPluginDiscovery,
} from "plugin-system";
const loader = new DefaultPluginLoader();
const discovery = new DefaultPluginDiscovery();
// Load plugin from file
const plugin = await loader.loadFromFile("./plugins/my-plugin.js");
// Batch load from directory
const plugins = await loader.loadFromDirectory("./plugins");
// Discover plugins
const descriptors = await discovery.discoverPlugins([
 "./plugins",
 "./custom-plugins",
]);

API Reference

PluginManager

Main plugin management class responsible for plugin lifecycle management.

Methods

  • registerPlugin(plugin, config?) - Register plugin
  • loadPlugin(name) - Load plugin
  • activatePlugin(name) - Activate plugin
  • deactivatePlugin(name) - Deactivate plugin
  • unloadPlugin(name) - Unload plugin
  • loadAll() - Batch load all plugins
  • activateAll() - Batch activate all plugins
  • deactivateAll() - Batch deactivate all plugins
  • getPlugin(name) - Get plugin instance
  • getActivePlugins() - Get active plugin list
  • updatePluginConfig(name, config) - Update plugin configuration

BasePlugin

Base plugin class providing fundamental plugin development functionality.

Lifecycle Methods

  • onInitialize() - Plugin initialization (must implement)
  • onActivate() - Plugin activation (must implement)
  • onDeactivate() - Plugin deactivation (must implement)
  • onDispose() - Plugin cleanup (must implement)
  • onConfigUpdate(config) - Configuration update (optional)
  • onDependencyStatusChange(dependency, status) - Dependency status change (optional)

Utility Methods

  • getConfig(key?) - Get configuration
  • getService(name) - Get service
  • getUtility(name) - Get utility
  • emit(event, data?) - Send event
  • on(event, listener) - Listen for event
  • off(event, listener) - Remove event listener

PluginStatus

Plugin status enumeration:

  • UNLOADED - Not loaded
  • LOADING - Loading
  • LOADED - Loaded
  • ACTIVE - Active
  • ERROR - Error
  • DISABLED - Disabled

Browser Support

Browser Quick Start

<!DOCTYPE html>
<html>
 <head>
 <title>Plugin System Browser Example</title>
 </head>
 <body>
 <!-- Load the built plugin system -->
 <script src="dist/browser/plugin-system.umd.js"></script>
 <script>
 async function init() {
 // Create browser plugin system
 const pluginSystem = PluginSystem.createBrowserPluginSystem();
 // Initialize default plugins (DOM and Storage)
 await pluginSystem.initializeWithDefaults();
 // Activate all plugins
 await pluginSystem.pluginManager.activateAll();
 // Use DOM plugin
 const domService = pluginSystem.pluginManager.getService("dom");
 const element = domService.createElement(
 "div",
 {
 style: "color: blue; padding: 10px;",
 },
 "Hello Plugin System!"
 );
 document.body.appendChild(element);
 // Use storage plugin
 const storageService = pluginSystem.pluginManager.getService("storage");
 storageService.local.set("greeting", "Hello World!");
 console.log(storageService.local.get("greeting"));
 }
 init().catch(console.error);
 </script>
 </body>
</html>

Browser-Specific Plugins

DOMPlugin - DOM Manipulation Plugin

Provides complete DOM manipulation and event management functionality:

// Get DOM service
const domService = pluginManager.getService("dom");
// Create elements
const button = domService.createElement(
 "button",
 {
 class: "my-button",
 id: "test-btn",
 },
 "Click Me"
);
// Add event listeners
domService.addEventListener(button, "click", () => {
 alert("Button clicked!");
});
// Create complex components
const component = domService.createComponent({
 tag: "div",
 className: "card",
 children: [
 { tag: "h3", textContent: "Title" },
 { tag: "p", textContent: "Content" },
 ],
 styles: {
 border: "1px solid #ccc",
 padding: "10px",
 borderRadius: "4px",
 },
});
// Observe DOM changes
domService.observeChanges(document.body, (mutations) => {
 console.log("DOM changed:", mutations);
});

StoragePlugin - Browser Storage Plugin

Supports localStorage, sessionStorage, and IndexedDB:

// Get storage service
const storageService = pluginManager.getService("storage");
// localStorage operations
storageService.local.set("user", { name: "John", age: 25 });
const user = storageService.local.get("user");
// sessionStorage operations
storageService.session.set("temp-data", "temporary value");
// IndexedDB operations (async)
await storageService.indexed.set("large-data", {
 /* large data */
});
const largeData = await storageService.indexed.get("large-data");
// Get storage statistics
const info = storageService.getInfo();
console.log("Storage usage:", info);

Browser Build

# Build browser version
npm run build:browser
# Build production version (minified)
npm run build:browser:dev

Built files are located in the dist/browser/ directory:

  • plugin-system.umd.js - UMD format
  • plugin-system.es.js - ES modules format

Development Scripts

# Node.js version
npm run build # Compile project
npm run example # Run basic example
npm run example:advanced # Run advanced example
# Browser version
npm run build:browser # Build browser version
npm run build:browser:dev # Build development version
# Development and testing
npm run dev:watch # Development mode (watch file changes)
npm run typecheck # Type checking
npm run lint # Code linting
npm run lint:fix # Fix code style
npm run test # Run tests
npm run test:watch # Run tests in watch mode
npm run test:coverage # Run tests with coverage
npm run test:ui # Run tests with UI
npm run clean # Clean build files

Example Projects

Check the examples/ directory for complete usage examples, including:

  • Plugin manager setup
  • Custom plugin creation
  • Service usage
  • Event handling
  • Configuration management
  • Batch operations

Run examples:

npm run example
npm run example:advanced

Best Practices

1. Plugin Design Principles

  • Single Responsibility - Each plugin focuses on one specific functionality
  • Loose Coupling - Communicate through services and events, avoid direct dependencies
  • Configurable - Provide flexible configuration options
  • Error Handling - Handle exceptions properly

2. Dependency Management

  • Clearly declare plugin dependencies
  • Avoid circular dependencies
  • Set reasonable plugin priorities
  • Handle dependency status changes

3. Performance Optimization

  • Lazy load non-critical plugins
  • Use cache services reasonably
  • Clean up resources promptly
  • Monitor memory usage

4. Error Handling

  • Implement complete error handling logic
  • Provide meaningful error messages
  • Support plugin degradation and recovery
  • Log detailed debugging information

Troubleshooting

Common Issues

1. Plugin Loading Failed

Problem: Plugin initialization failed

Solutions:

  • Check if plugin dependencies are correctly registered
  • Ensure plugin's onInitialize method doesn't throw exceptions
  • Verify plugin configuration is correct

2. Circular Dependency Error

Problem: Circular dependency detected

Solutions:

  • Redesign plugin architecture to avoid circular dependencies
  • Use event communication instead of direct dependencies
  • Consider extracting common dependencies into independent plugins

3. Service Not Found

Problem: Service not found

Solutions:

  • Ensure the service-providing plugin is activated
  • Check if service registration name is correct
  • Verify plugin loading order

4. Memory Leak

Problem: Memory usage continues to grow

Solutions:

  • Clean up all resources in plugin's onDispose method
  • Remove event listeners
  • Clear timers and async operations
  • Set reasonable size limits when using cache plugins

Debugging Tips

Enable Detailed Logging

// Set log level to debug
const logger = new ConsoleLogger();
logger.setLevel("debug");
// Or use built-in logger plugin
await pluginManager.updatePluginConfig("logger", {
 logLevel: "debug",
});

Monitor Plugin Status

// Listen for all plugin events
[
 "registered",
 "loaded",
 "activated",
 "deactivated",
 "unloaded",
 "config-changed",
].forEach((event) => {
 pluginManager.on(`plugin:${event}`, (data) => {
 console.log(`Plugin event [${event}]:`, data);
 });
});

Check Dependencies

// Get plugin dependency information
const plugin = pluginManager.getPlugin("my-plugin");
if (plugin) {
 console.log("Dependencies:", plugin.metadata.dependencies);
 console.log("Status:", plugin.status);
}
// Check all plugin statuses
const allPlugins = pluginManager.getAllPlugins();
for (const [name, plugin] of allPlugins) {
 console.log(`${name}: ${plugin.status}`);
}

Performance Optimization

1. Lazy Loading

// Only load plugins when needed
if (someCondition) {
 await pluginManager.loadPlugin("optional-plugin");
 await pluginManager.activatePlugin("optional-plugin");
}

2. Batch Operations

// Use batch operations instead of individual calls
await pluginManager.activateAll(); // Instead of multiple activatePlugin calls

3. Event Optimization

// Avoid frequent event sending
class MyPlugin extends BasePlugin {
 private eventBuffer: any[] = [];
 private flushEvents() {
 if (this.eventBuffer.length > 0) {
 this.emit("batch-events", this.eventBuffer);
 this.eventBuffer = [];
 }
 }
}

4. Memory Management

// Set reasonable limits when using cache plugins
await pluginManager.registerPlugin(cachePlugin, {
 maxSize: 1000, // Limit cache entries
 ttl: 300000, // Set expiration time
});
// Listen for memory warnings
pluginManager.on("system:memory-warning", () => {
 // Clean up non-essential resources
});

Extension Development

Create Plugin Template

# Create new plugin directory
mkdir my-plugin
cd my-plugin
# Create plugin file
cat > index.ts << 'EOF'
import { BasePlugin } from 'plugin-system';

export class MyPlugin extends BasePlugin {
 constructor() {
 super({
 name: 'my-plugin',
 version: '1.0.0',
 description: 'My custom plugin',
 author: 'Your Name'
 });
 }

 protected async onInitialize(): Promise<void> {
 // Initialization logic
 }

 protected async onActivate(): Promise<void> {
 // Activation logic
 }

 protected async onDeactivate(): Promise<void> {
 // Deactivation logic
 }

 protected async onDispose(): Promise<void> {
 // Cleanup logic
 }
}
EOF

Plugin Test Template

import { describe, it, expect, beforeEach, vi } from "vitest";
import { PluginManager } from "plugin-system";
import { MyPlugin } from "./my-plugin";
describe("MyPlugin", () => {
 let pluginManager: PluginManager;
 let plugin: MyPlugin;
 beforeEach(() => {
 pluginManager = new PluginManager(mockLogger);
 plugin = new MyPlugin();
 });
 it("should initialize correctly", async () => {
 await pluginManager.registerPlugin(plugin);
 await pluginManager.loadPlugin("my-plugin");
 expect(plugin.status).toBe(PluginStatus.LOADED);
 });
});

Deployment Guide

Production Configuration

// Recommended production configuration
const pluginManager = new PluginManager(productionLogger);
// Set up error handling
pluginManager.on("plugin:error", (error) => {
 // Send to monitoring system
 monitoring.reportError(error);
});
// Enable health checks
setInterval(() => {
 const health = getSystemHealth();
 if (!health.healthy) {
 // Trigger alerts
 alerting.sendAlert(health);
 }
}, 30000);

Docker Deployment

FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY dist ./dist
COPY plugins ./plugins
EXPOSE 3000
CMD ["node", "dist/index.js"]

Environment Variables

# .env file
PLUGIN_LOG_LEVEL=info
PLUGIN_CACHE_SIZE=1000
PLUGIN_DB_HOST=localhost
PLUGIN_DB_PORT=5432

Community Resources

Changelog

v1.0.0

  • Initial release
  • Basic plugin system functionality
  • Built-in logger and cache plugins
  • Complete TypeScript support

License

MIT License

Contributing

Issues and Pull Requests are welcome!

Contributing Guidelines

  1. Fork the project
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Development Setup

# Clone the project
git clone https://github.com/your-org/plugin-system.git
cd plugin-system
# Install dependencies
npm install
# Run tests
npm test
# Run examples
npm run example
npm run example:advanced
# Build project
npm run build

About

A flexible and extensible TypeScript/JavaScript plugin system supporting dependency management, lifecycle control, service registration, and event communication.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

AltStyle によって変換されたページ (->オリジナル) /