模块化插件需以状态驱动:插件作为订阅者监听特定字段,通过标准化元信息注册,由状态中枢通知变更;支持中间件链式处理冲突,并要求细粒度状态划分、卸载清理及延迟加载。

模块化是实现功能插件化的基础,但光有模块还不够——关键在于让插件能被动态识别、状态可感知、行为可协同。核心思路是:把插件定义为“带状态接口的独立模块”,由统一的状态中枢驱动其生命周期与交互。
插件即状态订阅者
每个插件不再主动轮询或硬编码触发逻辑,而是声明自己关心哪些状态字段(如 userRole、activeTab、isEditing),并在状态变更时自动响应。
- 插件导出一个 usePlugin 函数,内部调用 useSubscribe(['userRole', 'isEditing'])
- 状态中枢(如 Zustand store 或自研轻量 state bus)在 setState 后,只通知已订阅相关字段的插件
- 避免全局广播,减少无关重渲染;例如「权限插件」只监听 userRole,「草稿插件」只响应 isEditing
模块边界靠契约不靠路径
插件不是按文件夹位置加载,而是通过标准化元信息注册。一个插件包只需包含:
- manifest.json:声明 id、version、requiredStates、providesActions
- index.ts:默认导出 setup()(初始化)、mount()(挂载到 UI)、teardown()(卸载)
- states.ts(可选):定义该插件写入的状态片段,供其他插件读取
主应用通过 PluginLoader.loadFromUrl('/plugins/export-tool') 动态导入,无需构建时打包所有插件。
状态驱动的插件协同机制
多个插件可能修改同一状态(如「自动保存插件」和「离线缓存插件」都写 draftContent),需避免冲突:
- 采用「状态中间件」链式处理:每个插件可注册 beforeSet / afterSet 钩子
- 主状态更新前,依次执行所有 beforeSet(如校验格式、加锁标记);更新后触发 afterSet(如同步到 IndexedDB、发分析事件)
- 插件间通过状态字段间接通信,不直接调用对方方法,解耦且可热替换
实战中的关键细节
真正落地时容易卡在三处:
- 状态粒度要细:不要只暴露 appState 一个大对象,而应拆成 uiState、dataState、pluginState,方便按需订阅
- 插件卸载必须清理副作用:teardown() 中清除定时器、事件监听、state 订阅句柄,否则内存泄漏
- 首屏性能兼顾:非核心插件(如「暗色模式切换器」)可延迟加载,等主界面渲染完成再 loadPlugin('theme-switcher')










