UNPKG

mm_machine

Version:

这是超级美眉框架机制构建辅助模块,用于快速构建一个机制,支持动态加载、热更新、模块管理等功能,并具有增强的错误处理和现代JavaScript特性支持。

577 lines (436 loc) 15.3 kB
# mm_machine 一个灵活的Node.js插件化机制系统,用于动态加载、管理和执行模块。 ## 快速开始 ### 安装 ```bash npm install mm_machine --save ``` ### 目录结构 推荐的项目结构: ``` my_project/ ├── index.js # 主应用入口 ├── app/ # 默认模块目录 │ ├── module1/ # 模块1 │ │ ├── config_demo.json # 配置文件 (注意命名规则) │ │ └── index.js # 模块实现 │ └── module2/ # 模块2 │ ├── config_demo.json # 配置文件 │ └── main.js # 模块实现 (可以使用index.js或main.js) └── package.json ``` ### 使用示例 ```javascript const $ = require('mm_expand'); const Machine = require('mm_machine'); // 创建引擎实例 const engine = new Machine(); // 初始化并加载模块 async function init() { // 更新配置(可选) engine.update_config_all({ searchPath: './app/' // 默认路径,可自定义 }); // 加载所有模块 await engine.load_list(); // 执行所有模块的main方法 const results = await engine.execute('main'); $.log.debug('执行结果:', results); // 获取特定模块 const demo1 = engine.get('demo1'); if (demo1) { $.log.debug('找到模块:', demo1.name); } $.log.debug(`已加载 ${engine.list.length} 个模块`); } // 启动应用 init().catch(err => { $.log.error('初始化失败:', err); }); ``` ### 创建模块 **1. 创建配置文件** 在模块目录中创建 `config_demo.json` 文件(注意命名规则): ```json { "name": "demo1", "title": "测试模块1", "description": "这是第一个测试模块", "sort": 10, "state": 1, "show": 1, "config": { "debug": true, "timeout": 3000 } } ``` **2. 创建模块实现** 在同一目录中创建 `index.js` 或 `main.js` 文件: ```javascript const $ = require('mm_expand'); /** * 主方法 */ async function main() { $.log.info(`[${this.name}] 测试模块执行`); // 访问模块配置 const debug = this.config.debug; if (debug) { $.log.debug(`[${this.name}] 调试模式已启用`); } return { success: true, message: `${this.name} 执行成功` }; } // 导出方法 module.exports = { main }; ``` ### 重要:文件命名规则 **配置文件必须按照以下格式命名:** ``` config_{type}.json ``` 其中`{type}`必须与您在Engine类中设置的`this.type`属性值完全匹配。例如: - 如果`this.type = "demo"`,配置文件必须命名为`config_demo.json` - 如果`this.type = "plugin"`,配置文件必须命名为`config_plugin.json` ## 完整使用示例 ### 示例1:创建和管理基础模块 以下是一个完整的示例,展示如何创建和管理基础模块: **1. 项目结构** ``` my_project/ ├── index.js # 主应用入口 ├── app/ # 模块目录 │ ├── demo1/ # 模块1 │ │ ├── config_demo.json # 模块配置文件 │ │ └── index.js # 模块实现 │ └── demo2/ # 模块2 │ ├── config_demo.json # 模块配置文件 │ └── main.js # 模块实现 └── package.json ``` **2. 主应用入口 (`index.js`)** ```javascript const $ = require('mm_expand'); const Machine = require('mm_machine'); // 创建引擎实例 const engine = new Machine(); // 初始化引擎 async function init() { // 加载模块 await engine.load_list(); // 执行所有模块的main方法 await engine.execute('main'); // 获取特定模块 const demo1 = engine.get('demo1'); if (demo1) { $.log.debug('模块1状态:', demo1.state ? '启用' : '禁用'); // 执行特定模块的自定义方法 const result = await engine.execute('my_custom_method', 'demo1'); $.log.debug('自定义方法结果:', result); } // 监听文件变化(热更新模式) engine.mode = 2; engine.watch(); $.log.debug(`已加载 ${engine.list.length} 个模块`); } // 启动应用 init().catch(err => { $.log.error('初始化失败:', err); }); ``` **3. 模块配置文件示例 (`app/demo1/config_demo.json`)** ```json { "name": "demo1", "title": "测试模块1", "description": "这是第一个测试模块", "sort": 10, "state": 1, "show": 1, "config": { "debug": true, "timeout": 3000, "api_key": "your_api_key_here" } } ``` **4. 模块实现示例 (`app/demo1/index.js`)** ```javascript const $ = require('mm_expand'); // 模块状态变量 let counter = 0; /** * 初始化方法 */ async function init() { $.log.info(`[${this.name}] 模块初始化中...`); counter = 0; return true; } /** * 加载方法 */ async function load() { $.log.info(`[${this.name}] 模块加载中...`); // 可以在这里执行加载资源等操作 return true; } /** * 主方法 * @param {Object} params - 传入参数 */ async function main(params = {}) { $.log.info(`[${this.name}] 主方法执行,当前计数: ${counter++}`); // 访问模块配置 const debug = this.config.debug; if (debug) { $.log.debug(`[${this.name}] 调试模式已启用`); } // 返回结果 return { success: true, message: `${this.name} 执行成功`, count: counter, params: params }; } /** * 主方法执行前钩子 */ async function main_before() { $.log.info(`[${this.name}] 主方法执行前处理`); return true; } /** * 主方法执行后钩子 */ async function main_after(result) { $.log.info(`[${this.name}] 主方法执行后处理,结果:`, result); return result; } /** * 自定义方法 */ async function my_custom_method() { return { custom: "这是一个自定义方法", module_name: this.name }; } // 导出方法 module.exports = { init, load, main, main_before, main_after, my_custom_method }; ``` ### 示例2:使用自定义模块目录 如果需要使用非默认的模块目录,可以按以下方式配置: ```javascript const engine = new Machine(); // 使用自定义目录 engine.update_config_all({ searchPath: './custom_modules/' }); // 然后加载模块 await engine.load_list(); ``` ### 示例3:实现热更新和动态管理 以下示例展示如何实现模块的热更新和动态管理: ```javascript const engine = new Machine(); // 设置为热更新模式 engine.mode = 2; // 初始化 async function setup() { // 加载模块 await engine.load_list(); // 开始监听文件变化 engine.watch(); // 定时检查模块数量 setInterval(async () => { $.log.debug(`当前模块数量: ${engine.list.length}`); }, 5000); // 模拟动态管理模块 setTimeout(async () => { // 重载特定模块 await engine.reload('demo1'); $.log.debug('已重载模块 demo1'); }, 10000); setTimeout(async () => { // 卸载模块 await engine.unload('demo2'); $.log.debug('已卸载模块 demo2'); }, 20000); } setup().catch($.log.error); ``` ### 示例4:错误处理和异常捕获 ```javascript const engine = new Machine(); async function run() { try { // 加载模块并捕获可能的错误 await engine.load_list(); // 安全地执行模块方法 try { const result = await engine.execute('main'); $.log.debug('执行结果:', result); } catch (err) { $.log.error('执行方法时出错:', err); // 继续执行,不会中断整个应用 } // 单独执行特定模块并捕获可能的错误 try { const demo1Result = await engine.execute('main', 'demo1'); $.log.debug('demo1 执行结果:', demo1Result); } catch (err) { $.log.error('执行 demo1 时出错:', err); } } catch (err) { $.log.error('初始化失败:', err); } } run(); ``` ## 高级功能 ### 模块生命周期 每个模块支持完整的生命周期方法: - `init`: 模块初始化时调用 - `load`: 模块加载时调用 - `main`: 主执行方法 - `main_before`: 主方法执行前的钩子 - `main_after`: 主方法执行后的钩子 ### 运行模式说明 系统支持4种运行模式,可通过`mode`属性设置: 1. **生产模式** (`mode = 1`): 最高性能,文件改变不会触发重新加载 2. **热更新模式** (`mode = 2`): 文件改变时自动重新加载配置和代码 3. **重载模式** (`mode = 3`): 执行完后重新加载脚本,避免变量污染 4. **热更新+重载模式** (`mode = 4`): 结合热更新和重载的特性 ### 模块管理API ```javascript // 重载特定模块 await engine.reload("moduleName"); // 卸载模块(保留文件) await engine.unload("moduleName"); // 卸载并删除模块文件 await engine.unload("moduleName", true); // 保存模块配置 await engine.save(); // 获取特定模块 const module = engine.get("moduleName"); ``` ### 路径处理 - 所有相对路径都会基于模块的目录进行解析 - 使用`fullname()`方法可以获取绝对路径,避免路径问题 ## 常见问题与故障排除 ### 1. 模块无法加载 **检查项目:** - 确认配置文件命名格式正确 (`config_{type}.json`) - 确认`type`属性与配置文件前缀匹配 - 检查模块的`state`配置是否为1(启用) - 检查文件权限是否正确 ### 2. 热更新不工作 **检查项目:** - 确认`mode`设置为24(热更新模式) - 确认文件确实被修改了(注意编辑器的保存设置) - 检查文件路径是否正确 ### 3. 执行方法返回null **检查项目:** - 确认模块已正确加载 (`engine.list.length > 0`) - 确认方法名拼写正确 - 检查模块实现中是否正确导出了该方法 - 检查模块的`state`是否为1(启用状态) ### 4. 路径错误 **解决方案:** - 使用绝对路径或确保相对路径正确 - 利用`__dirname`和`fullname()`方法构建可靠的路径 ## 模块系统设计理念与工作流程 ### 设计理念 mm_machine 模块系统基于以下核心设计理念: 1. **高内聚、低耦合**:每个模块独立封装功能,通过明确的接口与其他模块交互 2. **可插拔架构**:模块可以动态加载、卸载,不影响系统整体运行 3. **配置驱动**:通过配置文件控制模块行为,无需修改代码 4. **生命周期管理**:提供完整的模块生命周期钩子,便于资源管理 5. **热更新支持**:无需重启应用即可更新模块功能 ### 工作流程 以下是模块系统的基本工作流程: ``` 初始化引擎 → 扫描模块目录 → 解析配置文件 → 加载模块代码 → 初始化模块 → 执行方法 → 监听文件变化(热更新模式) ``` 详细工作流程说明: 1. **初始化引擎**:创建 Machine 实例,设置配置项 2. **扫描模块目录**:根据 searchPath 扫描目录,查找 `config_{type}.json` 文件 3. **解析配置文件**:读取并解析配置,验证模块状态 4. **加载模块代码**:根据配置中的信息,动态加载模块的实现文件 5. **初始化模块**:按排序顺序初始化模块,执行 init 和 load 方法 6. **执行方法**:根据应用需求,执行模块的特定方法(如 main) 7. **监听文件变化**:在热更新模式下,监听文件变化并自动重新加载模块 ### 数据流向 模块间的数据流转遵循以下规则: 1. 引擎将调用参数传递给模块方法 2. 模块方法处理后返回结果 3. 钩子方法可以拦截和修改输入/输出数据 4. 模块可以访问自己的配置,但不能直接访问其他模块的数据 ## 最佳实践与开发建议 ### 模块设计最佳实践 1. **单一职责原则**:每个模块应专注于单一功能领域 2. **接口一致性**:遵循模块生命周期接口约定,确保兼容性 3. **错误处理**:在模块内部实现完善的错误处理机制 4. **日志记录**:使用统一的日志接口记录模块活动 5. **资源管理**:在适当的生命周期钩子中释放资源 ### 配置管理建议 1. **配置分层**:将公共配置和模块特有配置分开 2. **配置验证**:在模块初始化时验证配置有效性 3. **默认值处理**:为重要配置项提供合理的默认值 4. **敏感信息保护**:避免在配置文件中直接存储敏感信息 ### 性能优化建议 1. **懒加载**:对于资源密集型模块,考虑实现懒加载机制 2. **缓存策略**:合理使用缓存减少重复计算 3. **异步操作**:使用 async/await 处理异步操作,避免阻塞 4. **减少全局状态**:尽量减少模块间的状态共享 ### 调试技巧 1. **日志级别**:利用不同级别的日志(debug、info、error)辅助调试 2. **热更新调试**:使用热更新模式(mode=2)进行开发调试 3. **模块隔离**:出现问题时,尝试单独测试特定模块 4. **配置检查**:验证配置文件格式和内容是否正确 ### 部署注意事项 1. **生产环境模式**:部署到生产环境时,设置 mode=1 以获得最佳性能 2. **配置备份**:定期备份模块配置文件 3. **版本控制**:对模块代码和配置进行版本控制 4. **依赖管理**:明确声明和管理模块依赖 ## 贡献指南 如果您有兴趣为 mm_machine 项目贡献代码或改进,请遵循以下步骤: 1. Fork 项目仓库 2. 创建您的功能分支 (`git checkout -b feature/amazing-feature`) 3. 提交您的更改 (`git commit -m 'Add some amazing feature'`) 4. 推送到分支 (`git push origin feature/amazing-feature`) 5. 打开 Pull Request ## 更新日志 ### v1.0.0 (初始版本) - 基础模块管理功能 - 配置文件加载和解析 - 模块生命周期管理 - 热更新支持 - 基础错误处理 ### v1.1.0 - 改进模块加载逻辑,支持自定义目录 - 增强错误处理和异常捕获 - 添加更多生命周期钩子 - 优化性能和内存使用 ## 依赖 - mm_config: ^1.1.4 - mm_hot_reload: ^1.0.5 - mm_expand: 用于路径处理和文件操作 ## 许可证 ISC ## 作者信息 本模块由 mm_modules 团队开发和维护。如有问题或建议,请联系我们。