乐于分享
好东西不私藏

微内核/插件化架构 – 插件通信管理、插件生命周期 等的实现

微内核/插件化架构 – 插件通信管理、插件生命周期 等的实现

上一篇只是举了个微内核/插件化设计的例子,这一篇介绍加入 插件间的通信、插件生命周期管理 等内容,
有点类似 webpack 的打包过程中的 插件化机制。
主要实现 2 个插件的注册和应用:
1)生成 html 文件的插件
2)生成 md 文件的插件
本篇主要介绍:
1)定义插件管理器(微内核)
2)插件通信
3)根据插件协议定义插件
4)定义主入口文件、验证执行效果
1. 插件管理的核心(内核)
/*  pluginManager.js*/import { EventBus } from './eventBus.js';export class PluginManager {  constructor() {    this.plugins = new Map();    this.eventBus = new EventBus();  }  // 注册插件  use(plugin) {    this.plugins.set(plugin.name, plugin);    // 实现插件的生命周期管理,调用插件的初始化钩子函数。    // 同时把 eventBus 传递给插件,使得插件之间可以通过事件总线进行通信。    if (plugin.init) {      plugin.init({        ctx: this,        eventBus: this.eventBus      });    }    // 实现插件间的通信和协作    // 在插件注册后,触发一个事件,通知其他插件该插件已经初始化完成。    this.eventBus.emit(`${plugin.name}:init`, plugin);    // 模拟插件的 mount 生命周期钩子函数,在插件注册后触发一个事件,通知其他插件该插件已经挂载完成。    if (plugin.mount) {      plugin.mount({        ctx: this,        eventBus: this.eventBus      });      this.eventBus.emit(`${plugin.name}:mount`, plugin);    }  }  // 应用插件  apply(pluginName) {    const plugin = this.plugins.get(pluginName);    if (plugin && plugin.apply) {      plugin.apply({        ctx: this,        eventBus: this.eventBus      });    }  }  // 卸载插件  dispose(pluginName) {    const plugin = this.plugins.get(pluginName);    if (plugin && plugin.onUnmount) {      plugin.onUnmount({        ctx: this,        eventBus: this.eventBus      });    }  }}
2. 事件总线(实现插件间通信)
/*  eventBus.js*/export class EventBus {  constructor() {      this.events = {};  }  // on方法接受事件名称和回调函数,并将回调函数存储在events对象中,以便在事件触发时调用。  on(eventName, callback) {    if(!this.events[eventName]) {      this.events[eventName] = [];    }    this.events[eventName].push(callback);  }  // emit方法接受事件名称和任意数量的参数,并调用所有注册的回调函数,传递这些参数。  emit(eventName, ...args) {    if(this.events[eventName]) {      this.events[eventName].forEach(callback => {        callback.call(null, ...args)      });    }  }}

3. 根据插件协议定义插件
1)定义  htmlPlugin 
/*  文件路径:plugins/htmlPlugin.js*/import fs from "node:fs";// 设计插件协议export class HtmlPlugin {  constructor() {    this.name = "HtmlPlugin";  }  // init 生命周期钩子函数  init({ ctx, eventBus }) {    eventBus.on("MdPlugin:init"() => {      console.log("我是 HtmlPlugin, 我发现 MdPlugin 始化 init 了");    });    console.log("HtmlPlugin init ... ");  }  // mount 生命周期钩子函数  onMount() {    console.log("HtmlPlugin onMount");  }  // unmount 生命周期钩子函数  onUmount() {    console.log("HtmlPlugin onUnmount");  }  // apply 方法是插件的核心方法,可以在这里实现插件的主要功能。  apply({ ctx, eventBus }) {    // 类似 webpack 获取到 ctx(compiler) 以后可以订阅事件,处理资源,生成文件等。    console.log("HtmlPlugin 执行了,拿到了上下文对象:", ctx);    // 创建一个文件    fs.writeFileSync("dist/index.html""<div>Hello htmlPlugin</div>");  }}
2)定义 mdPlugin 插件
/*  文件路径:plugins/mdPlugin.js*/import fs from "node:fs";export class MdPlugin {  constructor() {    this.name = "MdPlugin";  }  init({ compiler, eventBus }) {    eventBus.emit("MdPlugin:init");    console.log("MdPlugin init");  }  onMount() {    console.log("MdPlugin onMount");  }  onUmount() {    console.log("MdPlugin onUnmount");  }  apply({ctx, eventBus}) {    console.log("MdPlugin 插件执行了,拿到上下文对象:", ctx);    fs.writeFileSync(      "dist/index.md",      `# frontend 学习\n> 我是 柠致, 欢迎来到我的前端学习之旅`    );  }}
4. 主入口文件 
在这儿 创建 插件管理器实例、注册插件、应用插件、卸载插件 等操作。
/*  index.js*/import { PluginManager } from './pluginManager.js';import { HtmlPlugin } from './plugins/htmlPlugin.js';import { MdPlugin } from './plugins/mdPlugin.js';// 创建插件管理器实例const pluginManager = new PluginManager();// 注册插件pluginManager.use(new HtmlPlugin());pluginManager.use(new MdPlugin());// 应用插件pluginManager.apply("HtmlPlugin");pluginManager.apply("MdPlugin");// 2000 ms 后,卸载 HtmlPlugin 插件setTimeout(() => {  pluginManager.dispose("HtmlPlugin");}, 2000);
5. 执行结果
在 dist 目录生成最终产物: