插件系统
Modern.js 采用高度可扩展的插件化架构,其核心功能和扩展能力均通过插件实现。插件系统不仅保证了框架的灵活性,也为开发者提供了强大的定制化手段。本文将重点介绍如何编写 Modern.js 插件,帮助您快速上手插件开发。
核心理念:一切皆插件
Modern.js 秉承“一切皆插件”的设计哲学,将框架的各项功能模块化,通过插件的形式进行组装和扩展。这种设计带来了诸多优势,包括:
- 高内聚,低耦合:各功能模块独立开发、测试和维护,降低系统复杂度。
- 灵活可扩展:用户可通过编写或组合插件,轻松定制框架行为,无需修改核心代码。
- 易于复用:插件可跨项目共享,提高开发效率。
- 渐进式增强:按需引入插件,无需一开始就承载所有功能的复杂性。
插件类型与适用场景
CLI 插件:
- 作用阶段:构建时(执行
modern命令时)。 - 典型场景:
- 扩展命令行工具。
- 修改构建配置。
- 监听文件变化。
- 控制构建流程。
- 配置方式:
modern.config.ts中的plugins字段。
Runtime 插件:
- 作用阶段:应用运行时(浏览器/Node.js 环境)。
- 典型场景:
- 初始化全局状态或服务。
- 封装 React 高阶组件(HOC)。
- 拦截或修改路由行为。
- 控制渲染流程。
- 配置方式:
src/modern.runtime.ts中的plugins字段。
插件结构
一个典型的 Modern.js 插件包含以下几个关键部分:
字段说明:
name
- 类型:
string - 说明:标识插件的名称。在插件体系中,该名称必须唯一,否则将导致插件加载失败。
Info
后续 pre, post, required 中声明的插件名称都是这里的 name 字段.
setup
- 类型:
(api: PluginAPI) => MaybePromise<void> - 说明:插件逻辑的主要入口。
api
- 类型:
PluginAPI - 说明:插件的 API,包含插件支持的 Hooks 和工具函数。
pre
- 类型:
string[] - 说明:用于插入插件执行顺序。在
pre中声明的插件会在此插件之前执行。
post
- 类型:
string[] - 说明:用于确定插件执行顺序。在
post中声明的插件会在此插件之后执行。
required
- 类型:
string[] - 说明:该插件依赖的其它插件。在运行前,会校验依赖的插件是否已注册。
Info
如果在 pre 或 post 中配置了未注册的插件名,这些插件名将被自动忽略,不会影响其他插件的执行。
如果需要明确声明当前插件依赖的插件必须存在,需要使用 required 字段。
usePlugins
- 类型:
Plugin - 说明:主动在插件中注册其他相同类型的插件。
Info
usePlugins 中声明的插件默认在当前插件之前执行。需要在其后执行,请使用 post 声明。
registryHooks
- 类型:
Record<string, PluginHook<(...args: any[]) => any>> - 说明:扩展当前支持的 Hook 函数,以实现自定义功能。
插件 Hook 模型
Modern.js 插件系统的核心是其 Hook 模型,它定义了插件之间的通信机制。Modern.js 主要提供两种 Hook 类型:
Async Hook(异步 Hook)
- 特点:
- Hook 函数异步执行,支持
async/await。 - 前一个 Hook 函数的返回值会作为下一个 Hook 函数的第一个参数。
- 最终返回最后一个 Hook 函数的返回值。
- Hook 函数异步执行,支持
- 适用场景:涉及异步操作的场景(如网络请求、文件读写等)。
- 创建方式:使用
createAsyncHook创建。
示例:
Sync Hook(同步 Hook)
- 特点:
- Hook 函数同步执行。
- 前一个 Hook 函数的返回值会作为下一个 Hook 函数的第一个参数。
- 最终返回最后一个 Hook 函数的返回值。
- 适用场景:需要同步修改数据的场景(如修改配置、路由等)。
- 创建方式:使用
createSyncHook创建。
示例:
插件开发最佳实践
- 单一职责: 每个插件应该专注于实现一个特定的、内聚的功能。避免创建功能庞杂、职责不清的插件。
- 命名规范: 插件名称应清晰、简洁, 并遵循一定的命名约定 (如
plugin-xxx或@scope/plugin-xxx). - 类型安全: 充分利用 TypeScript 的类型系统, 确保插件 API 的类型安全, 减少运行时错误。
- 文档完善: 为插件编写清晰的文档, 包括 API 说明、使用示例、配置项解释以及变更日志。
- 测试充分: 对插件进行单元测试和集成测试, 确保其稳定性、可靠性以及在各种场景下的兼容性。
- 减少副作用: 插件应该尽可能地减少对外部环境的修改 (如全局变量、文件系统等), 保持插件的独立性和可移植性。
- 错误处理: 插件内部应该妥善处理可能出现的错误, 避免因为插件的异常导致整个应用崩溃。
- 性能优化: 注意插件的性能影响, 避免不必要的计算和资源消耗, 特别是在循环或频繁调用的 Hook 中。
- 版本控制: 遵循语义化版本控制 (Semantic Versioning), 确保插件的向后兼容性, 方便用户升级。
遵循这些最佳实践, 可以帮助您开发出高质量、易维护、易使用的 Modern.js 插件。