第六章:高级特性实现
在前面的章节中,我们已经构建了一个功能完整的插件系统。现在我们要添加一些高级特性,让插件系统更加强大和实用,包括配置管理、条件加载、插件市场、热重载等企业级功能。
配置管理系统
1. 配置管理器
javascript
// config-manager.js
const path = require('path');
const fs = require('fs').promises;
class ConfigManager {
constructor(options = {}) {
this.configDir = options.configDir || './config';
this.defaultConfig = options.defaultConfig || {};
this.configs = new Map();
this.watchers = new Map();
this.validators = new Map();
this.transformers = new Map();
}
// 加载配置文件
async loadConfig(name, filePath) {
try {
const fullPath = path.resolve(this.configDir, filePath);
const content = await fs.readFile(fullPath, 'utf8');
let config;
if (filePath.endsWith('.json')) {
config = JSON.parse(content);
} else if (filePath.endsWith('.js')) {
// 动态导入 JS 配置文件
delete require.cache[require.resolve(fullPath)];
config = require(fullPath);
} else {
throw new Error(`Unsupported config file format: ${filePath}`);
}
// 应用转换器
if (this.transformers.has(name)) {
config = this.transformers.get(name)(config);
}
// 验证配置
if (this.validators.has(name)) {
const isValid = this.validators.get(name)(config);
if (!isValid) {
throw new Error(`Invalid configuration for ${name}`);
}
}
this.configs.set(name, config);
// 通知配置变化
this.notifyWatchers(name, config);
return config;
} catch (error) {
throw new Error(`Failed to load config ${name}: ${error.message}`);
}
}
// 保存配置文件
async saveConfig(name, filePath, config) {
try {
const fullPath = path.resolve(this.configDir, filePath);
// 确保目录存在
await fs.mkdir(path.dirname(fullPath), { recursive: true });
let content;
if (filePath.endsWith('.json')) {
content = JSON.stringify(config, null, 2);
} else if (filePath.endsWith('.js')) {
content = `module.exports = ${JSON.stringify(config, null, 2)};`;
} else {
throw new Error(`Unsupported config file format: ${filePath}`);
}
await fs.writeFile(fullPath, content, 'utf8');
this.configs.set(name, config);
this.notifyWatchers(name, config);
return true;
} catch (error) {
throw new Error(`Failed to save config ${name}: ${error.message}`);
}
}
// 获取配置
getConfig(name, key = null) {
const config = this.configs.get(name);
if (!config) {
return this.defaultConfig[name] || null;
}
if (key === null) {
return config;
}
// 支持点号路径,如 'database.host'
return this.getNestedValue(config, key);
}
// 设置配置
setConfig(name, key, value) {
let config = this.configs.get(name) || {};
if (typeof key === 'object') {
// 如果 key 是对象,则替换整个配置
config = key;
} else {
// 支持点号路径设置
config = this.setNestedValue(config, key, value);
}
// 验证配置
if (this.validators.has(name)) {
const isValid = this.validators.get(name)(config);
if (!isValid) {
throw new Error(`Invalid configuration for ${name}`);
}
}
this.configs.set(name, config);
this.notifyWatchers(name, config);
return config;
}
// 合并配置
mergeConfig(name, updates) {
const existing = this.configs.get(name) || {};
const merged = this.deepMerge(existing, updates);
return this.setConfig(name, merged);
}
// 监听配置变化
watchConfig(name, callback) {
if (!this.watchers.has(name)) {
this.watchers.set(name, []);
}
const watcherId = this.generateId();
this.watchers.get(name).push({ id: watcherId, callback });
// 返回取消监听的函数
return () => this.unwatchConfig(name, watcherId);
}
// 取消监听
unwatchConfig(name, watcherId) {
const watchers = this.watchers.get(name);
if (!watchers) return false;
const index = watchers.findIndex(w => w.id === watcherId);
if (index > -1) {
watchers.splice(index, 1);
if (watchers.length === 0) {
this.watchers.delete(name);
}
return true;
}
return false;
}
// 注册配置验证器
registerValidator(name, validator) {
this.validators.set(name, validator);
}
// 注册配置转换器
registerTransformer(name, transformer) {
this.transformers.set(name, transformer);
}
// 通知观察者
notifyWatchers(name, config) {
const watchers = this.watchers.get(name);
if (!watchers) return;
watchers.forEach(watcher => {
try {
watcher.callback(config, name);
} catch (error) {
console.error(`Error in config watcher for ${name}:`, error);
}
});
}
// 获取嵌套值
getNestedValue(obj, path) {
return path.split('.').reduce((current, key) => {
return current && current[key] !== undefined ? current[key] : undefined;
}, obj);
}
// 设置嵌套值
setNestedValue(obj, path, value) {
const keys = path.split('.');
const lastKey = keys.pop();
const target = keys.reduce((current, key) => {
if (!current[key] || typeof current[key] !== 'object') {
current[key] = {};
}
return current[key];
}, obj);
target[lastKey] = value;
return obj;
}
// 深度合并对象
deepMerge(target, source) {
const result = { ...target };
for (const key in source) {
if (source[key] && typeof source[key] === 'object' && !Array.isArray(source[key])) {
result[key] = this.deepMerge(result[key] || {}, source[key]);
} else {
result[key] = source[key];
}
}
return result;
}
// 生成唯一ID
generateId() {
return Math.random().toString(36).substr(2, 9);
}
// 获取所有配置名称
getConfigNames() {
return Array.from(this.configs.keys());
}
// 清空所有配置
clear() {
this.configs.clear();
this.watchers.clear();
}
}
module.exports = ConfigManager;
2. 条件加载系统
javascript
// conditional-loader.js
class ConditionalLoader {
constructor() {
this.conditions = new Map();
this.evaluators = new Map();
this.context = {};
}
// 注册条件评估器
registerEvaluator(name, evaluator) {
this.evaluators.set(name, evaluator);
}
// 设置上下文
setContext(context) {
this.context = { ...this.context, ...context };
}
// 注册插件加载条件
registerCondition(pluginName, condition) {
this.conditions.set(pluginName, condition);
}
// 评估是否应该加载插件
shouldLoadPlugin(pluginName) {
const condition = this.conditions.get(pluginName);
if (!condition) {
return true; // 没有条件则默认加载
}
return this.evaluateCondition(condition);
}
// 评估条件
evaluateCondition(condition) {
if (typeof condition === 'boolean') {
return condition;
}
if (typeof condition === 'function') {
return condition(this.context);
}
if (typeof condition === 'object') {
return this.evaluateComplexCondition(condition);
}
return true;
}
// 评估复杂条件
evaluateComplexCondition(condition) {
const { type, ...params } = condition;
switch (type) {
case 'and':
return params.conditions.every(c => this.evaluateCondition(c));
case 'or':
return params.conditions.some(c => this.evaluateCondition(c));
case 'not':
return !this.evaluateCondition(params.condition);
case 'env':
return this.evaluateEnvironmentCondition(params);
case 'config':
return this.evaluateConfigCondition(params);
case 'feature':
return this.evaluateFeatureCondition(params);
case 'custom':
return this.evaluateCustomCondition(params);
default:
console.warn(`Unknown condition type: ${type}`);
return true;
}
}
// 评估环境条件
evaluateEnvironmentCondition(params) {
const { variable, value, operator = 'equals' } = params;
const envValue = process.env[variable];
switch (operator) {
case 'equals':
return envValue === value;
case 'not_equals':
return envValue !== value;
case 'contains':
return envValue && envValue.includes(value);
case 'exists':
return envValue !== undefined;
case 'not_exists':
return envValue === undefined;
default:
return false;
}
}
// 评估配置条件
evaluateConfigCondition(params) {
const { key, value, operator = 'equals' } = params;
const configValue = this.getContextValue(key);
switch (operator) {
case 'equals':
return configValue === value;
case 'not_equals':
return configValue !== value;
case 'greater_than':
return configValue > value;
case 'less_than':
return configValue < value;
case 'contains':
return Array.isArray(configValue) && configValue.includes(value);
default:
return false;
}
}
// 评估特性条件
evaluateFeatureCondition(params) {
const { feature, enabled = true } = params;
const features = this.context.features || {};
return Boolean(features[feature]) === enabled;
}
// 评估自定义条件
evaluateCustomCondition(params) {
const { evaluator, ...args } = params;
const evaluatorFn = this.evaluators.get(evaluator);
if (!evaluatorFn) {
console.warn(`Custom evaluator not found: ${evaluator}`);
return true;
}
return evaluatorFn(args, this.context);
}
// 获取上下文值
getContextValue(key) {
return key.split('.').reduce((obj, k) => obj && obj[k], this.context);
}
// 获取所有条件
getAllConditions() {
return Object.fromEntries(this.conditions);
}
// 清空条件
clear() {
this.conditions.clear();
}
}
module.exports = ConditionalLoader;
3. 插件市场系统
javascript
// plugin-marketplace.js
const EventEmitter = require('events');
class PluginMarketplace extends EventEmitter {
constructor(options = {}) {
super();
this.registries = new Map();
this.cache = new Map();
this.downloadDir = options.downloadDir || './plugins';
this.cacheTimeout = options.cacheTimeout || 3600000; // 1小时
}
// 注册插件仓库
registerRegistry(name, registry) {
this.registries.set(name, {
...registry,
name,
lastSync: 0
});
}
// 搜索插件
async searchPlugins(query, options = {}) {
const { registry = null, category = null, limit = 50 } = options;
let results = [];
const registriesToSearch = registry ? [registry] : Array.from(this.registries.keys());
for (const registryName of registriesToSearch) {
try {
const registryResults = await this.searchInRegistry(registryName, query, { category, limit });
results = results.concat(registryResults.map(r => ({ ...r, registry: registryName })));
} catch (error) {
console.error(`Error searching in registry ${registryName}:`, error);
}
}
// 去重和排序
const uniqueResults = this.deduplicateResults(results);
return this.sortResults(uniqueResults, query);
}
// 在特定仓库中搜索
async searchInRegistry(registryName, query, options = {}) {
const registry = this.registries.get(registryName);
if (!registry) {
throw new Error(`Registry ${registryName} not found`);
}
// 检查缓存
const cacheKey = `search:${registryName}:${query}:${JSON.stringify(options)}`;
const cached = this.cache.get(cacheKey);
if (cached && Date.now() - cached.timestamp < this.cacheTimeout) {
return cached.data;
}
// 调用仓库的搜索API
let results;
if (registry.searchFunction) {
results = await registry.searchFunction(query, options);
} else if (registry.apiUrl) {
results = await this.searchViaAPI(registry, query, options);
} else {
throw new Error(`Registry ${registryName} has no search method`);
}
// 缓存结果
this.cache.set(cacheKey, {
data: results,
timestamp: Date.now()
});
return results;
}
// 通过API搜索
async searchViaAPI(registry, query, options) {
const url = new URL(registry.apiUrl + '/search');
url.searchParams.set('q', query);
if (options.category) {
url.searchParams.set('category', options.category);
}
if (options.limit) {
url.searchParams.set('limit', options.limit.toString());
}
const response = await fetch(url.toString());
if (!response.ok) {
throw new Error(`API request failed: ${response.statusText}`);
}
const data = await response.json();
return data.plugins || [];
}
// 获取插件详细信息
async getPluginInfo(pluginId, registry = null) {
if (registry) {
return await this.getPluginInfoFromRegistry(pluginId, registry);
}
// 在所有仓库中查找
for (const registryName of this.registries.keys()) {
try {
const info = await this.getPluginInfoFromRegistry(pluginId, registryName);
if (info) {
return { ...info, registry: registryName };
}
} catch (error) {
// 继续在其他仓库中查找
}
}
throw new Error(`Plugin ${pluginId} not found in any registry`);
}
// 从特定仓库获取插件信息
async getPluginInfoFromRegistry(pluginId, registryName) {
const registry = this.registries.get(registryName);
if (!registry) {
throw new Error(`Registry ${registryName} not found`);
}
// 检查缓存
const cacheKey = `info:${registryName}:${pluginId}`;
const cached = this.cache.get(cacheKey);
if (cached && Date.now() - cached.timestamp < this.cacheTimeout) {
return cached.data;
}
let info;
if (registry.getInfoFunction) {
info = await registry.getInfoFunction(pluginId);
} else if (registry.apiUrl) {
const response = await fetch(`${registry.apiUrl}/plugins/${pluginId}`);
if (!response.ok) {
throw new Error(`Plugin ${pluginId} not found`);
}
info = await response.json();
} else {
throw new Error(`Registry ${registryName} has no info method`);
}
// 缓存结果
this.cache.set(cacheKey, {
data: info,
timestamp: Date.now()
});
return info;
}
// 下载插件
async downloadPlugin(pluginId, version = 'latest', registry = null) {
const pluginInfo = await this.getPluginInfo(pluginId, registry);
const targetRegistry = registry || pluginInfo.registry;
this.emit('download:start', { pluginId, version, registry: targetRegistry });
try {
const downloadUrl = await this.getDownloadUrl(pluginId, version, targetRegistry);
const filePath = await this.downloadFile(downloadUrl, pluginId, version);
this.emit('download:complete', { pluginId, version, filePath });
return {
pluginId,
version,
filePath,
info: pluginInfo
};
} catch (error) {
this.emit('download:error', { pluginId, version, error });
throw error;
}
}
// 获取下载URL
async getDownloadUrl(pluginId, version, registryName) {
const registry = this.registries.get(registryName);
if (registry.getDownloadUrlFunction) {
return await registry.getDownloadUrlFunction(pluginId, version);
} else if (registry.apiUrl) {
const response = await fetch(`${registry.apiUrl}/plugins/${pluginId}/download?version=${version}`);
const data = await response.json();
return data.downloadUrl;
} else {
throw new Error(`Registry ${registryName} has no download method`);
}
}
// 下载文件
async downloadFile(url, pluginId, version) {
// 这里应该实现实际的文件下载逻辑
// 为了示例,我们只是模拟下载过程
const fileName = `${pluginId}-${version}.zip`;
const filePath = path.join(this.downloadDir, fileName);
// 模拟下载进度
for (let i = 0; i <= 100; i += 10) {
this.emit('download:progress', { pluginId, version, progress: i });
await new Promise(resolve => setTimeout(resolve, 100));
}
return filePath;
}
// 去重结果
deduplicateResults(results) {
const seen = new Set();
return results.filter(result => {
const key = `${result.id}:${result.version}`;
if (seen.has(key)) {
return false;
}
seen.add(key);
return true;
});
}
// 排序结果
sortResults(results, query) {
return results.sort((a, b) => {
// 按相关性排序(简单的字符串匹配)
const aRelevance = this.calculateRelevance(a, query);
const bRelevance = this.calculateRelevance(b, query);
if (aRelevance !== bRelevance) {
return bRelevance - aRelevance;
}
// 按下载量排序
return (b.downloads || 0) - (a.downloads || 0);
});
}
// 计算相关性
calculateRelevance(plugin, query) {
const queryLower = query.toLowerCase();
let score = 0;
if (plugin.name && plugin.name.toLowerCase().includes(queryLower)) {
score += 10;
}
if (plugin.description && plugin.description.toLowerCase().includes(queryLower)) {
score += 5;
}
if (plugin.keywords && plugin.keywords.some(k => k.toLowerCase().includes(queryLower))) {
score += 3;
}
return score;
}
// 清空缓存
clearCache() {
this.cache.clear();
}
// 获取统计信息
getStats() {
return {
registries: this.registries.size,
cacheSize: this.cache.size,
registryList: Array.from(this.registries.keys())
};
}
}
module.exports = PluginMarketplace;
4. 热重载系统
javascript
// hot-reload-manager.js
const fs = require('fs');
const path = require('path');
const EventEmitter = require('events');
class HotReloadManager extends EventEmitter {
constructor(pluginManager, options = {}) {
super();
this.pluginManager = pluginManager;
this.watchedFiles = new Map();
this.watchers = new Map();
this.reloadQueue = [];
this.isReloading = false;
this.options = {
watchDelay: 1000,
maxRetries: 3,
...options
};
}
// 启用热重载
enable() {
this.emit('hot-reload:enabled');
}
// 禁用热重载
disable() {
this.stopWatching();
this.emit('hot-reload:disabled');
}
// 监听插件文件变化
watchPlugin(pluginName, filePaths) {
if (!Array.isArray(filePaths)) {
filePaths = [filePaths];
}
filePaths.forEach(filePath => {
const absolutePath = path.resolve(filePath);
// 检查文件是否存在
if (!fs.existsSync(absolutePath)) {
console.warn(`File not found for watching: ${absolutePath}`);
return;
}
// 如果已经在监听,先停止
if (this.watchers.has(absolutePath)) {
this.watchers.get(absolutePath).close();
}
// 创建文件监听器
const watcher = fs.watch(absolutePath, { persistent: false }, (eventType) => {
if (eventType === 'change') {
this.scheduleReload(pluginName, absolutePath);
}
});
this.watchers.set(absolutePath, watcher);
this.watchedFiles.set(absolutePath, pluginName);
this.emit('file:watched', { pluginName, filePath: absolutePath });
});
}
// 停止监听插件
unwatchPlugin(pluginName) {
const filesToUnwatch = [];
for (const [filePath, watchedPluginName] of this.watchedFiles) {
if (watchedPluginName === pluginName) {
filesToUnwatch.push(filePath);
}
}
filesToUnwatch.forEach(filePath => {
const watcher = this.watchers.get(filePath);
if (watcher) {
watcher.close();
this.watchers.delete(filePath);
}
this.watchedFiles.delete(filePath);
});
this.emit('plugin:unwatched', { pluginName });
}
// 停止所有监听
stopWatching() {
for (const watcher of this.watchers.values()) {
watcher.close();
}
this.watchers.clear();
this.watchedFiles.clear();
}
// 安排重载
scheduleReload(pluginName, filePath) {
// 防抖处理
const existingIndex = this.reloadQueue.findIndex(item => item.pluginName === pluginName);
if (existingIndex > -1) {
clearTimeout(this.reloadQueue[existingIndex].timeoutId);
this.reloadQueue.splice(existingIndex, 1);
}
const timeoutId = setTimeout(() => {
this.executeReload(pluginName, filePath);
}, this.options.watchDelay);
this.reloadQueue.push({
pluginName,
filePath,
timeoutId,
timestamp: Date.now()
});
this.emit('reload:scheduled', { pluginName, filePath });
}
// 执行重载
async executeReload(pluginName, filePath) {
if (this.isReloading) {
// 如果正在重载,延迟执行
setTimeout(() => this.executeReload(pluginName, filePath), 100);
return;
}
this.isReloading = true;
try {
this.emit('reload:start', { pluginName, filePath });
const plugin = this.pluginManager.getPlugin(pluginName);
if (!plugin) {
throw new Error(`Plugin ${pluginName} not found`);
}
// 保存插件状态
const wasEnabled = plugin.state === 'enabled';
const pluginConfig = this.pluginManager.getPluginConfig?.(pluginName);
// 禁用插件
if (wasEnabled) {
await this.pluginManager.disablePlugin(pluginName);
}
// 清除模块缓存
this.clearModuleCache(filePath);
// 重新加载插件
const newPluginClass = this.loadPluginClass(filePath);
const newPlugin = new newPluginClass();
// 替换插件实例
await this.replacePlugin(pluginName, newPlugin, pluginConfig);
// 如果之前是启用状态,重新启用
if (wasEnabled) {
await this.pluginManager.enablePlugin(pluginName);
}
this.emit('reload:success', { pluginName, filePath });
} catch (error) {
this.emit('reload:error', { pluginName, filePath, error });
console.error(`Hot reload failed for plugin ${pluginName}:`, error);
// 尝试恢复
await this.attemptRecovery(pluginName);
} finally {
this.isReloading = false;
}
}
// 清除模块缓存
clearModuleCache(filePath) {
const absolutePath = path.resolve(filePath);
// 删除主模块缓存
delete require.cache[absolutePath];
// 删除相关依赖的缓存
const moduleDir = path.dirname(absolutePath);
Object.keys(require.cache).forEach(cachedPath => {
if (cachedPath.startsWith(moduleDir)) {
delete require.cache[cachedPath];
}
});
}
// 加载插件类
loadPluginClass(filePath) {
try {
const pluginModule = require(path.resolve(filePath));
// 支持不同的导出方式
if (typeof pluginModule === 'function') {
return pluginModule;
} else if (pluginModule.default && typeof pluginModule.default === 'function') {
return pluginModule.default;
} else if (pluginModule.Plugin && typeof pluginModule.Plugin === 'function') {
return pluginModule.Plugin;
} else {
throw new Error('Plugin class not found in module');
}
} catch (error) {
throw new Error(`Failed to load plugin class: ${error.message}`);
}
}
// 替换插件实例
async replacePlugin(pluginName, newPlugin, config) {
// 卸载旧插件
await this.pluginManager.unloadPlugin(pluginName);
// 注册新插件
await this.pluginManager.register(newPlugin);
// 恢复配置
if (config && this.pluginManager.setPluginConfig) {
this.pluginManager.setPluginConfig(pluginName, config);
}
// 初始化新插件
await this.pluginManager.initPlugin(pluginName);
}
// 尝试恢复
async attemptRecovery(pluginName) {
try {
// 尝试重新启用插件
const plugin = this.pluginManager.getPlugin(pluginName);
if (plugin && plugin.state === 'error') {
await plugin.recover();
await this.pluginManager.enablePlugin(pluginName);
this.emit('recovery:success', { pluginName });
}
} catch (error) {
this.emit('recovery:failed', { pluginName, error });
}
}
// 手动重载插件
async reloadPlugin(pluginName) {
const filePaths = [];
for (const [filePath, watchedPluginName] of this.watchedFiles) {
if (watchedPluginName === pluginName) {
filePaths.push(filePath);
}
}
if (filePaths.length === 0) {
throw new Error(`No watched files found for plugin ${pluginName}`);
}
// 使用第一个文件路径进行重载
await this.executeReload(pluginName, filePaths[0]);
}
// 获取监听状态
getWatchStatus() {
const status = {};
for (const [filePath, pluginName] of this.watchedFiles) {
if (!status[pluginName]) {
status[pluginName] = [];
}
status[pluginName].push(filePath);
}
return {
watchedPlugins: Object.keys(status).length,
watchedFiles: this.watchedFiles.size,
details: status,
isReloading: this.isReloading,
queueSize: this.reloadQueue.length
};
}
}
module.exports = HotReloadManager;
集成高级特性的插件管理器
javascript
// enterprise-plugin-manager.js
const CommunicationEnabledPluginManager = require('../chapter-05/communication-enabled-plugin-manager');
const ConfigManager = require('./config-manager');
const ConditionalLoader = require('./conditional-loader');
const PluginMarketplace = require('./plugin-marketplace');
const HotReloadManager = require('./hot-reload-manager');
class EnterprisePluginManager extends CommunicationEnabledPluginManager {
constructor(options = {}) {
super();
// 初始化高级特性
this.configManager = new ConfigManager(options.config);
this.conditionalLoader = new ConditionalLoader();
this.marketplace = new PluginMarketplace(options.marketplace);
this.hotReloadManager = new HotReloadManager(this, options.hotReload);
// 插件配置存储
this.pluginConfigs = new Map();
// 设置条件加载上下文
this.updateConditionalContext();
// 监听配置变化
this.setupConfigWatchers();
}
// 更新条件加载上下文
updateConditionalContext() {
this.conditionalLoader.setContext({
environment: process.env.NODE_ENV || 'development',
platform: process.platform,
features: this.configManager.getConfig('features', {}) || {},
config: this.getAllConfigs()
});
}
// 设置配置监听器
setupConfigWatchers() {
// 监听特性配置变化
this.configManager.watchConfig('features', () => {
this.updateConditionalContext();
});
// 监听插件配置变化
this.configManager.watchConfig('plugins', (config) => {
this.handlePluginConfigChange(config);
});
}
// 处理插件配置变化
async handlePluginConfigChange(config) {
for (const [pluginName, pluginConfig] of Object.entries(config)) {
const plugin = this.getPlugin(pluginName);
if (plugin && plugin.onConfigChange) {
try {
await plugin.onConfigChange(pluginConfig);
} catch (error) {
console.error(`Error applying config change to plugin ${pluginName}:`, error);
}
}
}
}
// 重写插件注册方法,添加条件检查
async register(plugin, options = {}) {
// 检查加载条件
if (!this.conditionalLoader.shouldLoadPlugin(plugin.name)) {
this.context.log(`Plugin ${plugin.name} skipped due to loading conditions`);
return this;
}
// 加载插件配置
await this.loadPluginConfig(plugin.name);
// 注册热重载
if (options.watchFiles && this.hotReloadManager) {
this.hotReloadManager.watchPlugin(plugin.name, options.watchFiles);
}
return await super.register(plugin);
}
// 加载插件配置
async loadPluginConfig(pluginName) {
try {
const configPath = `plugins/${pluginName}.json`;
const config = await this.configManager.loadConfig(pluginName, configPath);
this.pluginConfigs.set(pluginName, config);
} catch (error) {
// 配置文件不存在或加载失败,使用默认配置
this.pluginConfigs.set(pluginName, {});
}
}
// 获取插件配置
getPluginConfig(pluginName) {
return this.pluginConfigs.get(pluginName) || {};
}
// 设置插件配置
async setPluginConfig(pluginName, config) {
this.pluginConfigs.set(pluginName, config);
// 保存到文件
const configPath = `plugins/${pluginName}.json`;
await this.configManager.saveConfig(pluginName, configPath, config);
// 通知插件配置变化
const plugin = this.getPlugin(pluginName);
if (plugin && plugin.onConfigChange) {
await plugin.onConfigChange(config);
}
}
// 从市场安装插件
async installFromMarketplace(pluginId, version = 'latest', registry = null) {
try {
// 下载插件
const downloadResult = await this.marketplace.downloadPlugin(pluginId, version, registry);
// 解压和安装插件(这里简化处理)
const pluginPath = await this.extractPlugin(downloadResult.filePath);
// 加载插件类
const PluginClass = require(pluginPath);
const plugin = new PluginClass();
// 注册插件
await this.register(plugin, {
watchFiles: [pluginPath],
fromMarketplace: true,
marketplaceInfo: downloadResult.info
});
return plugin;
} catch (error) {
throw new Error(`Failed to install plugin ${pluginId}: ${error.message}`);
}
}
// 解压插件(简化实现)
async extractPlugin(filePath) {
// 这里应该实现实际的解压逻辑
// 为了示例,我们假设直接返回插件文件路径
return filePath.replace('.zip', '.js');
}
// 设置加载条件
setLoadingCondition(pluginName, condition) {
this.conditionalLoader.registerCondition(pluginName, condition);
}
// 启用热重载
enableHotReload() {
this.hotReloadManager.enable();
}
// 禁用热重载
disableHotReload() {
this.hotReloadManager.disable();
}
// 获取所有配置
getAllConfigs() {
const configs = {};
for (const name of this.configManager.getConfigNames()) {
configs[name] = this.configManager.getConfig(name);
}
return configs;
}
// 获取系统状态(扩展版本)
getSystemStatus() {
const baseStatus = super.getSystemStatus();
return {
...baseStatus,
config: {
loadedConfigs: this.configManager.getConfigNames().length,
pluginConfigs: this.pluginConfigs.size
},
conditionalLoader: {
conditions: Object.keys(this.conditionalLoader.getAllConditions()).length
},
marketplace: this.marketplace.getStats(),
hotReload: this.hotReloadManager.getWatchStatus()
};
}
// 清理资源
async cleanup() {
this.hotReloadManager.disable();
this.configManager.clear();
this.conditionalLoader.clear();
this.marketplace.clearCache();
await super.cleanup();
}
}
module.exports = EnterprisePluginManager;
使用示例
让我们创建一个完整的示例来展示这些高级特性:
配置文件示例
json
// config/features.json
{
"hotReload": true,
"marketplace": true,
"analytics": false,
"debugMode": true
}
json
// config/plugins/logger.json
{
"level": "info",
"format": "json",
"outputs": ["console", "file"],
"file": {
"path": "./logs/app.log",
"maxSize": "10MB",
"maxFiles": 5
}
}
示例插件
javascript
// advanced-logger-plugin.js
const EnhancedPlugin = require('../chapter-04/enhanced-plugin');
class AdvancedLoggerPlugin extends EnhancedPlugin {
constructor() {
super('logger', '2.0.0', {
description: 'Advanced logging plugin with configuration support'
});
this.config = {};
this.loggers = new Map();
}
async init(context) {
this.context = context;
// 获取插件配置
this.config = context.getPluginConfig?.(this.name) || {
level: 'info',
format: 'text',
outputs: ['console']
};
// 初始化日志器
this.initializeLoggers();
// 注册日志服务
context.services.register('logService', () => ({
log: (level, message, meta) => this.log(level, message, meta),
createLogger: (name) => this.createLogger(name),
setLevel: (level) => this.setLevel(level)
}));
context.log('Advanced logger initialized with config:', this.config);
}
// 配置变化处理
async onConfigChange(newConfig) {
this.context.log('Logger config changed:', newConfig);
this.config = { ...this.config, ...newConfig };
this.initializeLoggers();
}
// 初始化日志器
initializeLoggers() {
// 根据配置初始化不同的日志输出
this.loggers.clear();
if (this.config.outputs.includes('console')) {
this.loggers.set('console', {
write: (message) => console.log(message)
});
}
if (this.config.outputs.includes('file')) {
this.loggers.set('file', {
write: (message) => {
// 这里应该实现文件写入逻辑
console.log(`[FILE] ${message}`);
}
});
}
}
// 记录日志
log(level, message, meta = {}) {
if (!this.shouldLog(level)) {
return;
}
const logEntry = this.formatMessage(level, message, meta);
for (const logger of this.loggers.values()) {
logger.write(logEntry);
}
}
// 检查是否应该记录日志
shouldLog(level) {
const levels = ['debug', 'info', 'warn', 'error'];
const currentLevelIndex = levels.indexOf(this.config.level);
const messageLevelIndex = levels.indexOf(level);
return messageLevelIndex >= currentLevelIndex;
}
// 格式化消息
formatMessage(level, message, meta) {
const timestamp = new Date().toISOString();
if (this.config.format === 'json') {
return JSON.stringify({
timestamp,
level,
message,
meta,
plugin: this.name
});
} else {
return `[${timestamp}] ${level.toUpperCase()}: ${message}`;
}
}
// 创建命名日志器
createLogger(name) {
return {
debug: (message, meta) => this.log('debug', `[${name}] ${message}`, meta),
info: (message, meta) => this.log('info', `[${name}] ${message}`, meta),
warn: (message, meta) => this.log('warn', `[${name}] ${message}`, meta),
error: (message, meta) => this.log('error', `[${name}] ${message}`, meta)
};
}
// 设置日志级别
setLevel(level) {
this.config.level = level;
this.context.log(`Log level changed to: ${level}`);
}
}
module.exports = AdvancedLoggerPlugin;
完整使用示例
javascript
// enterprise-example.js
const EnterprisePluginManager = require('./enterprise-plugin-manager');
const AdvancedLoggerPlugin = require('./advanced-logger-plugin');
async function main() {
const pluginManager = new EnterprisePluginManager({
config: {
configDir: './config'
},
marketplace: {
downloadDir: './downloaded-plugins'
},
hotReload: {
watchDelay: 500
}
});
try {
console.log('=== 加载系统配置 ===');
// 加载特性配置
await pluginManager.configManager.loadConfig('features', 'features.json');
// 设置条件加载规则
pluginManager.setLoadingCondition('analytics', {
type: 'and',
conditions: [
{ type: 'feature', feature: 'analytics', enabled: true },
{ type: 'env', variable: 'NODE_ENV', value: 'production' }
]
});
pluginManager.setLoadingCondition('debugger', {
type: 'config',
key: 'features.debugMode',
value: true
});
console.log('\n=== 注册插件 ===');
// 注册插件(带热重载支持)
const loggerPlugin = new AdvancedLoggerPlugin();
await pluginManager.register(loggerPlugin, {
watchFiles: ['./advanced-logger-plugin.js']
});
// 启用热重载
pluginManager.enableHotReload();
console.log('\n=== 初始化和启用插件 ===');
await pluginManager.initAll();
await pluginManager.enableAll();
console.log('\n=== 测试配置管理 ===');
// 获取日志服务
const logService = pluginManager.context.communication.serviceRegistry.get('logger.logService');
// 测试日志功能
logService.log('info', 'System started successfully');
logService.log('debug', 'Debug information', { userId: 123 });
// 动态更改插件配置
console.log('\n--- 更改日志配置 ---');
await pluginManager.setPluginConfig('logger', {
level: 'debug',
format: 'json',
outputs: ['console', 'file']
});
// 测试配置变化后的日志
logService.log('debug', 'This should now be visible');
console.log('\n=== 测试插件市场 ===');
// 注册一个模拟的插件仓库
pluginManager.marketplace.registerRegistry('official', {
apiUrl: 'https://api.example.com/plugins',
searchFunction: async (query) => {
// 模拟搜索结果
return [
{
id: 'cache-plugin',
name: 'Cache Plugin',
version: '1.0.0',
description: 'High-performance caching plugin',
downloads: 1500,
keywords: ['cache', 'performance']
}
];
}
});
// 搜索插件
const searchResults = await pluginManager.marketplace.searchPlugins('cache');
console.log('Search results:', searchResults);
console.log('\n=== 系统状态 ===');
const status = pluginManager.getSystemStatus();
console.log('Plugin count:', status.total);
console.log('Config status:', status.config);
console.log('Hot reload status:', status.hotReload);
console.log('Marketplace stats:', status.marketplace);
console.log('\n=== 测试热重载 ===');
console.log('Hot reload is enabled. Try modifying the plugin file to see hot reload in action.');
// 监听热重载事件
pluginManager.hotReloadManager.on('reload:success', ({ pluginName }) => {
console.log(`🔥 Plugin ${pluginName} hot reloaded successfully!`);
});
pluginManager.hotReloadManager.on('reload:error', ({ pluginName, error }) => {
console.error(`❌ Hot reload failed for ${pluginName}:`, error.message);
});
// 保持程序运行以测试热重载
console.log('\nPress Ctrl+C to exit...');
process.on('SIGINT', async () => {
console.log('\n=== 清理资源 ===');
await pluginManager.cleanup();
process.exit(0);
});
} catch (error) {
console.error('Error:', error);
await pluginManager.cleanup();
}
}
main().catch(console.error);
运行结果
运行上面的示例代码,你会看到类似这样的输出:
=== 加载系统配置 ===
=== 注册插件 ===
🔄 logger: unregistered -> registered
📦 Plugin registered: logger v2.0.0
=== 初始化和启用插件 ===
Advanced logger initialized with config: { level: 'info', format: 'json', outputs: ['console', 'file'] }
🔄 logger: resolved -> initialized
Advanced logger enabled
🔄 logger: initialized -> enabled
=== 测试配置管理 ===
{"timestamp":"2024-01-15T10:30:00.000Z","level":"info","message":"System started successfully","meta":{},"plugin":"logger"}
--- 更改日志配置 ---
Logger config changed: { level: 'debug', format: 'json', outputs: ['console', 'file'] }
{"timestamp":"2024-01-15T10:30:01.000Z","level":"debug","message":"This should now be visible","meta":{},"plugin":"logger"}
=== 测试插件市场 ===
Search results: [
{
id: 'cache-plugin',
name: 'Cache Plugin',
version: '1.0.0',
description: 'High-performance caching plugin',
downloads: 1500,
keywords: ['cache', 'performance'],
registry: 'official'
}
]
=== 系统状态 ===
Plugin count: 1
Config status: { loadedConfigs: 2, pluginConfigs: 1 }
Hot reload status: { watchedPlugins: 1, watchedFiles: 1, isReloading: false }
Marketplace stats: { registries: 1, cacheSize: 1, registryList: ['official'] }
小结
在这一章中,我们实现了插件系统的高级特性,包括:
- 配置管理系统:支持动态配置加载、验证、转换和监听
- 条件加载系统:根据环境、配置、特性等条件决定插件加载
- 插件市场系统:支持插件搜索、下载和安装
- 热重载系统:支持插件的热更新,提高开发效率
- 企业级插件管理器:集成所有高级特性的完整解决方案
这些高级特性让插件系统具备了企业级应用的能力:
- 灵活的配置管理
- 智能的条件加载
- 丰富的插件生态
- 高效的开发体验
在下一章中,我们将通过一个实战案例来展示如何构建一个类似 Vite 的构建工具插件系统。
练习题
- 实现插件的版本管理和兼容性检查功能
- 添加插件的性能监控和分析功能
- 实现插件的A/B测试功能,支持灰度发布
下一章预告:我们将通过构建一个完整的构建工具来展示插件系统的实际应用。