首页
/ Modern.js 框架插件开发指南:扩展自定义 Hook 模型

Modern.js 框架插件开发指南:扩展自定义 Hook 模型

2025-07-08 07:00:54作者:廉皓灿Ida

前言

Modern.js 作为一款现代化的前端开发框架,其插件系统提供了强大的扩展能力。本文将深入讲解如何在 Modern.js 中通过动态注册 Hook 模型来扩展插件功能,帮助开发者构建更灵活的插件体系。

什么是 Hook 模型

Hook 模型是 Modern.js 插件系统的核心机制之一,它允许插件在特定生命周期节点注入自定义逻辑。通过 Hook 模型,不同插件可以在不直接耦合的情况下相互协作。

Modern.js 内置了多种 Hook 类型,包括:

  • Waterfall(瀑布流):前一个插件的输出作为下一个插件的输入
  • Bail(保险丝):任一插件返回非 undefined 值则终止后续执行
  • Parallel(并行):所有插件并行执行

创建自定义 Hook

1. 初始化项目

首先确保你已经创建了一个 Modern.js 项目。如果尚未创建,可以通过以下命令初始化:

npx @modern-js/create@latest modern-js-demo

2. 定义 Hook 模型

我们以创建一个控制台消息收集 Hook 为例:

import { createWaterfall } from '@modern-js/plugin';

// 创建一个 Waterfall 类型的 Hook,用于收集字符串数组
const message = createWaterfall<string[]>();

这里我们选择了 Waterfall 类型,因为消息收集通常需要将多个插件的输出串联起来。

3. 注册 Hook 模型

在插件中注册我们定义的 Hook:

import type { CliPlugin } from '@modern-js/core';

export const myPlugin = (): CliPlugin => ({
  name: 'my-plugin',
  registerHook: {
    message,  // 注册自定义 Hook
  },
});

4. 扩展类型声明

为了让 TypeScript 能够识别我们的新 Hook,需要扩展核心类型:

declare module '@modern-js/core' {
  export interface Hooks {
    message: typeof message;  // 将 message Hook 添加到类型系统
  }
}

使用自定义 Hook

1. 创建命令调用 Hook

我们可以在插件中创建一个命令来触发 Hook 执行:

setup(api) {
  return {
    commands({ program }) {
      program.command('message').action(async () => {
        const hookRunners = api.useHookRunners();
        // 执行 message Hook,初始传入空数组
        const messages = hookRunners.message([]);
        console.log(messages.join('\n'));
      });
    },
  };
}

2. 完整插件代码

将以上部分组合起来,完整的插件代码如下:

import { createWaterfall } from '@modern-js/plugin';
import type { CliPlugin } from '@modern-js/core';

const message = createWaterfall<string[]>();

export const myPlugin = (): CliPlugin => ({
  name: 'my-plugin',
  registerHook: {
    message,
  },
  setup(api) {
    return {
      commands({ program }) {
        program.command('message').action(async () => {
          const hookRunners = api.useHookRunners();
          const messages = hookRunners.message([]);
          console.log(messages.join('\n'));
        });
      },
    };
  },
});

declare module '@modern-js/core' {
  export interface Hooks {
    message: typeof message;
  }
}

3. 配置插件

在项目配置文件中启用我们的插件:

import { defineConfig } from '@modern-js/app-tools';
import { myPlugin } from './config/plugin/myPlugin';

export default defineConfig({
  plugins: [myPlugin()],
});

扩展 Hook 功能

1. 创建提供消息的插件

现在我们可以创建另一个插件来提供消息内容:

import type { CliPlugin } from '@modern-js/core';

export const otherPlugin = (): CliPlugin => ({
  name: 'other-plugin',
  setup(api) {
    return {
      message(list) {
        // 在现有列表基础上添加两条消息
        return [...list, '[foo] line 0', '[foo] line 1'];
      },
    };
  },
});

2. 更新配置

同时启用两个插件:

import { defineConfig } from '@modern-js/app-tools';
import { myPlugin } from './config/plugin/myPlugin';
import { otherPlugin } from './config/plugin/otherPlugin';

export default defineConfig({
  plugins: [myPlugin(), otherPlugin()],
});

3. 运行命令

现在执行命令可以看到输出:

npx modern message
[foo] line 0
[foo] line 1

高级用法

多插件协作

多个插件可以共同贡献内容到同一个 Hook:

// 第三个插件
export const thirdPlugin = (): CliPlugin => ({
  name: 'third-plugin',
  setup(api) {
    return {
      message(list) {
        return [...list, '[bar] additional message'];
      },
    };
  },
});

配置三个插件后,输出将包含所有插件的贡献:

[foo] line 0
[foo] line 1
[bar] additional message

Hook 执行顺序

Hook 的执行顺序通常由插件注册顺序决定。Modern.js 提供了优先级机制来控制执行顺序:

export const highPriorityPlugin = (): CliPlugin => ({
  name: 'high-priority-plugin',
  pre: ['my-plugin', 'other-plugin'], // 确保在其他插件之前执行
  setup(api) {
    // ...
  },
});

总结

通过扩展 Hook 模型,Modern.js 插件可以实现高度灵活的协作模式。本文展示了:

  1. 如何创建自定义 Hook 模型
  2. 如何注册和使用 Hook
  3. 多插件如何通过 Hook 协作
  4. 控制 Hook 执行顺序的方法

这种机制使得 Modern.js 插件系统具备了极强的扩展性,开发者可以根据项目需求自由组合各种功能插件。