@spes/react-plugins
v0.0.9
Published
Use your react component as plugins!
Readme
@spes/react-plugins
将 React 组件作为插件使用,专为超大型前端项目设计的插件化架构解决方案
核心特性
- 模块化架构:支持多模块、多命名空间的插件管理
- 依赖解析:自动解析插件依赖关系,支持版本约束和可选依赖
- 循环依赖检测:运行时和构建时双重检测,提供可视化报告
- 生命周期管理:完整的插件生命周期(注册→激活→停用→销毁)
- 服务注册中心:模块间服务发现机制,支持跨模块服务调用
- 事件系统:基于命名空间的事件总线,支持插件间通信
- 虚拟化渲染:支持大量插件的虚拟化渲染,优化性能
- 严格类型:完整的 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示例包含:
- 基础插件注册和使用
- 模块化管理
- 依赖注入
- 事件通信
- 虚拟化渲染
- 热插拔架构
- 远程动态加载
技术限制
- React 版本:需要 React 16.8+(Hooks 支持)
- TypeScript:推荐使用 TS 3.7+ 以获得最佳类型推断
- 浏览器支持:依赖 ES2015+ 特性,IE 需要 polyfill
- 性能:大量插件(>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
