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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@spes/react-plugins

v0.0.9

Published

Use your react component as plugins!

Readme

@spes/react-plugins

将 React 组件作为插件使用,专为超大型前端项目设计的插件化架构解决方案

NPM JavaScript Style Guide

核心特性

  • 模块化架构:支持多模块、多命名空间的插件管理
  • 依赖解析:自动解析插件依赖关系,支持版本约束和可选依赖
  • 循环依赖检测:运行时和构建时双重检测,提供可视化报告
  • 生命周期管理:完整的插件生命周期(注册→激活→停用→销毁)
  • 服务注册中心:模块间服务发现机制,支持跨模块服务调用
  • 事件系统:基于命名空间的事件总线,支持插件间通信
  • 虚拟化渲染:支持大量插件的虚拟化渲染,优化性能
  • 严格类型:完整的 TypeScript 类型支持
  • Webpack 插件:构建时循环依赖检测和报告生成
  • 热插拔架构:支持 Base + 子模块的动态加载/卸载
  • 远程加载:支持 Nginx 部署的远程动态插件加载

安装

npm install --save @spes/react-plugins

依赖要求:

  • React >= 16.8.0(支持 Hooks)
  • TypeScript >= 3.7(推荐)

快速开始

1. 创建 PluginStore

import { PluginStore } from '@spes/react-plugins';

const store = new PluginStore();
export default store;

2. 包裹应用组件

import React from 'react';
import { PluginStoreProvider } from '@spes/react-plugins';
import store from './pluginStore';
import App from './App';

const Root = () => (
  <PluginStoreProvider store={store}>
    <App />
  </PluginStoreProvider>
);

export default Root;

3. 注册插件

import store from './pluginStore';
import MyWidget from './components/MyWidget';

// 基础注册
store.registerPlugin('sidebar', MyWidget, 'my-widget', 10);

// 带依赖的注册
store.registerPlugin('sidebar', {
  component: MyWidget,
  name: 'my-widget',
  version: '1.0.0',
  dependencies: ['user-profile@^1.0.0'],  // 依赖其他插件
  optionalDependencies: ['theme-plugin']  // 可选依赖
});

// 完整配置(推荐)
store.registerPlugin('sidebar', {
  component: MyWidget,
  name: 'my-widget',
  version: '1.0.0',
  module: 'user-module',
  dependencies: ['user-profile'],
  auto: true,      // 自动加载
  lazy: true       // 懒加载
});

4. 使用插件

import React from 'react';
import { usePlugins } from '@spes/react-plugins';

const Sidebar = () => {
  const plugins = usePlugins('sidebar');
  
  return (
    <div className="sidebar">
      {plugins.map((Plugin, index) => (
        <Plugin key={index} />
      ))}
    </div>
  );
};

核心 API

PluginStore

插件存储的核心类,管理所有插件的注册、依赖解析和生命周期。

class PluginStore {
  // 基础注册
  registerPlugin(
    section: string,
    component: ComponentType | ReactElement,
    name: string,
    priority?: number
  ): void;

  // 选项式注册(推荐)
  registerPlugin(
    section: string,
    options: PluginOption
  ): void;

  // 移除插件
  removePlugin(section: string, name: string): void;

  // 获取插件
  getPlugin(section: string, name: string): PluginOption | undefined;
  getPlugins(section: string): PluginOption[];
  getSections(): string[];

  // 事件系统
  on(event: string, callback: PluginEventCallback, namespace?: string): () => void;
  emit(event: string, data?: any): void;
  broadcast(section: string, event: string, data?: any): void;
}

Hooks

usePlugins

获取指定 section 的所有插件组件。

const plugins = usePlugins('sidebar');

usePluginStatus

监听插件状态变化。

const status = usePluginStatus('sidebar', 'my-widget');
// status: { loaded: boolean; version?: string; dependencies: {...} }

usePluginEvent

订阅插件事件。

usePluginEvent('plugin:registered', (data) => {
  console.log('Plugin registered:', data);
});

usePluginDependencies

获取插件依赖信息。

const deps = usePluginDependencies('my-widget');
// deps: { satisfied: boolean; missing: string[]; ... }

useVirtualPlugins

虚拟化渲染大量插件。

const { virtualItems, containerRef, totalHeight } = useVirtualPlugins({
  section: 'sidebar',
  itemHeight: 50,
  overscan: 5
});

高级功能

模块管理

适用于超大型项目的模块化管理:

import { ModuleManager } from '@spes/react-plugins';

const manager = new ModuleManager();

// 注册模块
manager.registerModule({
  name: 'billing',
  version: '2.0.0',
  dependencies: ['user', 'auth']  // 依赖其他模块
});

// 检查模块依赖
const result = manager.checkModuleDependencies('billing');
console.log(result.satisfied);  // true/false

// 获取加载顺序(拓扑排序)
const order = manager.resolveModuleOrder();
// ['auth', 'user', 'billing']

生命周期管理

import { PluginLifecycle } from '@spes/react-plugins';

const lifecycle = new PluginLifecycle();

// 订阅生命周期事件
lifecycle.subscribe((event) => {
  console.log(event.type, event.pluginName, event.currentState);
});

// 手动控制生命周期
await lifecycle.activate('my-plugin');
await lifecycle.deactivate('my-plugin');
await lifecycle.destroy('my-plugin');

服务注册中心(ServiceRegistry)

提供模块间服务发现机制,实现松耦合的跨模块服务调用。

设计原则:只提供机制,不存储业务数据。ServiceRegistry 仅存储服务实例的引用,不存储任何业务数据(如用户信息、token 等)。

import { serviceRegistry } from '@spes/react-plugins';

// ========== 模块注册服务 ==========

// user 模块注册其服务
class UserService {
  async getCurrentUser() { /* ... */ }
  async login(params) { /* ... */ }
}

const userService = new UserService();

// 注册服务(模块启动时)
serviceRegistry.register('userService', userService, {
  module: 'user',
  version: '1.0.0',
  description: '用户服务'
});

// ========== 其他模块获取服务 ==========

// cluster 模块获取 userService
const userService = serviceRegistry.getService<UserService>('userService');

if (userService) {
  const user = await userService.getCurrentUser();
}

// ========== 服务发现 API ==========

// 检查服务是否存在
if (serviceRegistry.has('userService')) { /* ... */ }

// 等待服务可用(异步)
const userService = await serviceRegistry.waitFor<UserService>('userService', 5000);

// 获取模块的所有服务
const userServices = serviceRegistry.getServicesByModule('user');

// 获取所有服务名称
const allServices = serviceRegistry.getServiceNames();

// 获取服务元信息
const meta = serviceRegistry.getServiceMeta('userService');
// { name: 'userService', module: 'user', version: '1.0.0', registeredAt: 1234567890 }

// ========== 服务变更监听 ==========

const unsubscribe = serviceRegistry.subscribe((event) => {
  if (event.type === 'register') {
    console.log(`服务 ${event.name} 已注册`);
  } else {
    console.log(`服务 ${event.name} 已注销`);
  }
});

// 取消订阅
unsubscribe();

// ========== 模块卸载时注销服务 ==========

serviceRegistry.unregister('userService');

与模块系统联动

// user 模块入口 (index.ts)
import { serviceRegistry, ModuleManager, PluginStore, globalEventBus } from '@spes/react-plugins';
import { userService } from './services/UserService';
import { plugins } from './plugins';

const moduleDeclaration = {
  name: 'user',
  version: '1.0.0',
  dependencies: ['core']
};

if (typeof window !== 'undefined') {
  // 1. 注册模块
  const moduleManager = new ModuleManager();
  moduleManager.registerModule(moduleDeclaration);
  
  // 2. 注册服务
  serviceRegistry.register('userService', userService, { module: 'user' });
  
  // 3. 注册插件
  const pluginStore = new PluginStore();
  plugins.forEach(plugin => {
    pluginStore.registerPlugin(plugin.section || 'default', plugin);
  });
  
  // 4. 触发事件
  globalEventBus.emit('module:ready', { name: 'user' });
}

架构边界

| 能力 | PluginStore | ModuleManager | ServiceRegistry | |------|-------------|---------------|------------------| | UI组件插件 | ✅ | ❌ | ❌ | | 模块依赖管理 | ❌ | ✅ | ❌ | | 服务实例注册 | ❌ | ❌ | ✅ | | 服务发现/获取 | ❌ | ❌ | ✅ | | 存储业务数据 | ❌ | ❌ | ❌(禁止) |

循环依赖检测

import { CircularDependencyDetector } from '@spes/react-plugins';

const detector = new CircularDependencyDetector();

// 添加插件
detector.addPlugin({
  metadata: { name: 'plugin-a', version: '1.0.0' },
  component: ComponentA,
  dependencies: ['plugin-b']
});

// 检测循环依赖
const report = detector.detectAtRuntime();
if (report.hasCircular) {
  console.log('循环链:', report.cycles);
  console.log('严重程度:', report.severity);
}

// 生成可视化图表
const mermaidDiagram = detector.generateMermaidDiagram();
const dotGraph = detector.generateDotGraph();

Webpack 插件

构建时循环依赖检测:

// webpack.config.js
const { ReactPluginsWebpackPlugin } = require('@spes/react-plugins/webpack');

module.exports = {
  plugins: [
    new ReactPluginsWebpackPlugin({
      detectCircularDependency: true,
      circularDependencyThreshold: 0,  // 超过此数量报错
      ignoreNodeModules: true,
      generateReport: true,
      reportOutputPath: 'plugin-dependency-report.json',
      generateVisualization: true,  // 生成 Mermaid/DOT 图表
      failOnError: 'warn'  // 'error' | 'warn' | 'silent'
    })
  ]
};

类型定义

PluginOption

interface PluginOption {
  // ========== 核心属性 ==========
  component: ComponentType | ReactElement;
  name?: string;
  
  // ========== 模块属性 ==========
  module?: string;
  section?: string;
  
  // ========== 版本和元数据 ==========
  version?: string;
  displayName?: string;
  description?: string;
  
  // ========== 依赖控制 ==========
  dependencies?: string[];
  optionalDependencies?: string[];
  
  // ========== 加载控制(声明式优先级) ==========
  auto?: boolean;        // 自动加载
  before?: string;       // 在此插件之前渲染
  after?: string;        // 在此插件之后渲染
  
  // ========== 懒加载 ==========
  lazy?: boolean;
  lazyConfig?: {
    preload?: 'immediate' | 'lazy' | 'idle' | 'visible';
    timeout?: number;
  };
  placeholder?: ComponentType;  // 懒加载占位符
  
  // ========== 权限控制 ==========
  permissions?: string[];
  roles?: string[];
  
  // ========== 性能预算 ==========
  memoryBudget?: number;   // 内存预算(MB)
  renderBudget?: number;   // 渲染性能预算(ms)
  
  // ========== 错误处理 ==========
  errorBoundary?: ComponentType<{ error: Error; reset: () => void }>;
  throwOnError?: boolean;
  
  // ========== 生命周期 ==========
  lifecycle?: {
    beforeActivate?: () => boolean | Promise<boolean>;
    onActivate?: () => void | Promise<void>;
    beforeDeactivate?: () => boolean | Promise<boolean>;
    onDeactivate?: () => void | Promise<void>;
    onDestroy?: () => void;
  };
  
  // ========== 国际化 ==========
  i18n?: {
    languages: string[];
  };
  
  // ========== 调试 ==========
  tags?: string[];
  debug?: {
    verbose?: boolean;
    performance?: boolean;
  };
  
  // ========== 作者信息 ==========
  author?: {
    name: string;
    email?: string;
    organization?: string;
  };
  
  // ========== 时间戳 ==========
  createdAt?: string;
  updatedAt?: string;
}

PluginState

enum PluginState {
  REGISTERED = 'registered',    // 已注册但未激活
  ACTIVATING = 'activating',    // 正在激活
  ACTIVE = 'active',            // 已激活
  DEACTIVATING = 'deactivating', // 正在停用
  INACTIVE = 'inactive',        // 已停用
  ERROR = 'error',              // 发生错误
  DESTROYED = 'destroyed'       // 已销毁
}

错误处理

import {
  PluginError,
  PluginDependencyError,
  PluginVersionError,
  PluginCircularDependencyError,
  PluginNotFoundError
} from '@spes/react-plugins';

try {
  store.registerPlugin('section', config);
} catch (error) {
  if (error instanceof PluginCircularDependencyError) {
    console.log('循环链:', error.cycle);
  } else if (error instanceof PluginDependencyError) {
    console.log('缺失依赖:', error.missingDependencies);
  }
}

性能优化

虚拟化渲染

import { useVirtualPlugins } from '@spes/react-plugins';

const VirtualSidebar = () => {
  const { virtualItems, containerRef, totalHeight } = useVirtualPlugins({
    section: 'sidebar',
    itemHeight: 60,
    overscan: 3,
    containerHeight: 600
  });

  return (
    <div ref={containerRef} style={{ height: 600, overflow: 'auto' }}>
      <div style={{ height: totalHeight }}>
        {virtualItems.map(({ item, style, index }) => (
          <div key={index} style={style}>
            <item.component />
          </div>
        ))}
      </div>
    </div>
  );
};

懒加载

store.registerPlugin('section', {
  component: LazyComponent,
  name: 'lazy-plugin',
  version: '1.0.0',
  lazy: true,
  lazyConfig: {
    preload: 'visible',
    timeout: 5000
  }
});

热插拔架构(Base + 子模块)

适用于微前端、插件化系统场景:

// Base 项目
import { HotPlugManager, PluginStore, ModuleManager } from '@spes/react-plugins';

const store = new PluginStore();
const moduleManager = new ModuleManager();
const hotPlug = new HotPlugManager(store, moduleManager, {
  interval: 3000,      // 3秒检测一次
  autoRegister: true,  // 自动注册
  autoUnregister: true // 自动卸载
});

hotPlug.startDetection();
// 子模块(独立构建部署)
const ModuleADeclaration = {
  version: '1.0.0',
  plugins: [
    {
      section: 'sidebar',
      config: { component: Widget, name: 'widget', version: '1.0.0' }
    }
  ]
};

// 自动注册到 Base
(window as any).__PLUGIN_MODULES__ = {
  ...(window as any).__PLUGIN_MODULES__,
  'module-a': ModuleADeclaration
};

快速生成子模块

使用 CLI 工具快速创建符合规范的子模块:

# 生成模块
node scripts/generate-plugin.js \
  --name=order-module \
  --component=OrderList \
  --section=dashboard \
  --version=1.0.0 \
  --lazy=true

# 构建模块
cd order-module
npm install
npm run build

# 部署到 Nginx
cp dist/order-module.js /var/www/plugins/

远程动态加载(Nginx 部署)

支持从服务端动态加载插件:

import { RemotePluginLoader } from '@spes/react-plugins';

const loader = new RemotePluginLoader(store, moduleManager, {
  pluginsEndpoint: '/api/plugins',   // 插件列表 API
  pluginsBasePath: '/plugins/',       // 插件文件路径
  checkInterval: 30000                // 30秒检测一次
});

// 启动自动加载
await loader.start();

// 手动加载
await loader.loadPlugin({ name: 'module-a', file: 'module-a.js', version: '1.0.0' });

// 上传并加载
await loader.uploadAndLoad(file);

示例项目

查看 example 目录获取完整示例:

cd example
npm install
npm start

示例包含:

  • 基础插件注册和使用
  • 模块化管理
  • 依赖注入
  • 事件通信
  • 虚拟化渲染
  • 热插拔架构
  • 远程动态加载

技术限制

  1. React 版本:需要 React 16.8+(Hooks 支持)
  2. TypeScript:推荐使用 TS 3.7+ 以获得最佳类型推断
  3. 浏览器支持:依赖 ES2015+ 特性,IE 需要 polyfill
  4. 性能:大量插件(>1000)建议使用虚拟化渲染

架构图

+-------------------------------------------------------------+
|                      React Plugins                          |
+-------------------------------------------------------------+
|  +--------------+  +--------------+  +--------------+      |
|  |   Hooks      |  |  Components  |  |    Store     |      |
|  |  usePlugins  |  |   Plugins    |  | PluginStore  |      |
|  | usePluginEvent|  |   Provider   |  |              |      |
|  +------+-------+  +------+-------+  +------+-------+      |
|         +-----------------+------------------+              |
|                           |                                 |
|  +------------------------+------------------------+       |
|  |                   Core Layer                      |       |
|  |  +--------------+ +--------------+ +----------+  |       |
|  |  |ModuleManager | |DependencyResolver| |PluginLifecycle|  |
|  |  +--------------+ +--------------+ +----------+  |       |
|  |  +--------------+ +--------------+ +----------+  |       |
|  |  |ServiceRegistry| |   EventBus   | |HotPlugManager|  |
|  |  | (服务发现)   | +--------------+ +----------+  |       |
|  |  +--------------+ +--------------+ +----------+  |       |
|  |  |CircularDependency| |RemotePluginLoader|       |       |
|  |  |   Detector   | +---------------------+       |       |
|  |  +--------------+                               |       |
|  +--------------------------------------------------+       |
|                           |                                 |
|  +------------------------+------------------------+       |
|  |                   Utils Layer                     |       |
|  |  +--------------+ +--------------+ +----------+  |       |
|  |  | pluginErrors | |dependencyManager| |  store   |  |    |
|  |  +--------------+ +--------------+ +----------+  |       |
|  +--------------------------------------------------+       |
+-------------------------------------------------------------+

许可证

MIT