Modern.js 采用高度可扩展的插件化架构,其核心功能和扩展能力均通过插件实现。插件系统不仅保证了框架的灵活性,也为开发者提供了强大的定制化手段。本文将重点介绍如何编写 Modern.js 插件,帮助您快速上手插件开发。
Modern.js 秉承“一切皆插件”的设计哲学,将框架的各项功能模块化,通过插件的形式进行组装和扩展。这种设计带来了诸多优势,包括:
CLI 插件:
modern 命令时)。modern.config.ts 中的 plugins 字段。Runtime 插件:
src/modern.runtime.ts 中的 plugins 字段。一个典型的 Modern.js 插件包含以下几个关键部分:
import type { Plugin } from '@modern-js/plugin';
const myPlugin: Plugin = {
name: 'my-awesome-plugin', // 插件的唯一标识符(必需)
// 插件依赖和执行顺序(可选)
pre: [], // 在此插件之前执行的插件名列表,默认为空数组
post: [], // 在此插件之后执行的插件名列表,默认为空数组
required: [], // 必需的插件列表,若依赖的插件未注册,则会报错,默认为空数组
usePlugins: [], // 内部使用的插件实例列表,默认为空数组
// 注册新的 Hook (可选)
registryHook: {},
// 插件的入口函数(必需)
setup(api) {
// 插件的核心逻辑,通过 api 对象调用插件 API
api.modifyWebpackConfig(config => {
/* ... */
});
api.onPrepare(() => {
/* ... */
});
// ... 其他 API 调用
},
};
export default myPlugin;字段说明:
namestring
后续 pre, post, required 中声明的插件名称都是这里的 name 字段.
setup(api: PluginAPI) => MaybePromise<void>apiPluginAPIprestring[]pre 中声明的插件会在此插件之前执行。poststring[]post 中声明的插件会在此插件之后执行。requiredstring[]
如果在 pre 或 post 中配置了未注册的插件名,这些插件名将被自动忽略,不会影响其他插件的执行。
如果需要明确声明当前插件依赖的插件必须存在,需要使用 required 字段。
usePluginsPlugin
usePlugins 中声明的插件默认在当前插件之前执行。需要在其后执行,请使用 post 声明。
registryHooksRecord<string, PluginHook<(...args: any[]) => any>>Modern.js 插件系统的核心是其 Hook 模型,它定义了插件之间的通信机制。Modern.js 主要提供两种 Hook 类型:
async/await。createAsyncHook 创建。示例:
// 定义 Hooks
import { createAsyncHook } from '@modern-js/plugin';
export type AfterPrepareFn = () => Promise<void> | void;
export const onAfterPrepare = createAsyncHook<AfterPrepareFn>();
// 插件中注册 Hooks
const myPlugin = () => ({
name: 'my-plugin',
registryHooks: {
onAfterPrepare,
},
setup: api => {
api.onPrepare(async () => {
// 插件中使用注册的 Hooks
const hooks = api.getHooks();
await hooks.onAfterPrepare.call();
});
},
});
// 在其他插件中使用 Hook
const myPlugin2 = () => ({
name: 'my-plugin-2',
setup: api => {
api.onAfterPrepare(async () => {
// TOOD
});
},
});createSyncHook 创建。示例:
// 定义 Hooks
import { createSyncHook } from '@modern-js/plugin';
type RouteObject = {
/** TODO **/
};
const modifyRoutes = createSyncHook<(routes: RouteObject[]) => RouteObject[]>();
// 插件中注册 Hooks
const myPlugin = () => ({
name: 'my-plugin',
registryHooks: {
modifyRoutes,
},
setup: api => {
api.onPrepare(async () => {
const routes = {};
// 在插件中使用注册的 Hooks
const hooks = api.getHooks();
const routesResult = hooks.modifyRoutes.call(routes);
});
},
});
// 其他插件使用 Hooks
const myPlugin2 = () => ({
name: 'my-plugin',
setup: api => {
api.modifyRoutes(async routes => {
// 修改 routes
return routes;
});
},
});plugin-xxx 或 @scope/plugin-xxx).遵循这些最佳实践, 可以帮助您开发出高质量、易维护、易使用的 Modern.js 插件。