Plugin Hooks

This chapter describes the lifecycle hooks supported by module-tools.

Currently there are following main types of lifecycle hooks.

  • Config hooks: change user config.
  • Build hooks: triggered only when the build command is executed to build the source code product.
  • buildPlatform hook: triggered only when the build --platform command is executed to generate other build artifacts.
  • dev hooks: hooks that are triggered when running the dev command.

Hook Model is explained in detail here.

Config hooks

resolveModuleUserConfig

chang user config.

type: AsyncWaterfall

export const myPlugin = (): CliPlugin<ModuleTools> => ({
  name: 'my-plugin',

  setup() {
    return {
      resolveModuleUserConfig(config: ModuleUserConfig): ModuleUserConfig {},
    };
  },
});

build hooks

The following Hooks are triggered in order when the build command is executed.

  • beforeBuild
  • beforeBuildTask
  • afterBuildTask
  • afterBuild

beforeBuild

Triggered before the execution of the overall build process.

type: ParallelWorkflow

export const myPlugin = (): CliPlugin<ModuleTools> => ({
  name: 'my-plugin',

  setup() {
    return {
      beforeBuild(options: Options): void {},
    };
  },
});

Parameters value types.

type Options = {
  options: { config: BaseBuildConfig[]; cliOptions: BuildCommandOptions };
};

export interface BuildCommandOptions {
  config: string;
  clear?: boolean;
  dts?: boolean;
  platform?: boolean | string[];
  tsconfig: string;
  watch?: boolean;
}

BuildConfig type reference API configuration

beforeBuildTask

Based on the build configuration, Modern.js Module will split the overall build into multiple sub-build tasks. The Hook will be triggered before each build subtask.

type: AsyncWaterfall

export const myPlugin = (): CliPlugin<ModuleTools> => ({
  name: 'my-plugin',

  setup() {
    return {
      beforeBuildTask(config: BaseBuildConfig): BaseBuildConfig {
        return config;
      },
    };
  },
});

Parameters and return value types.

BaseBuildConfig type reference API configuration

afterBuildTask

Triggered after the end of each build subtask.

type: ParallelWorkflow

export const myPlugin = (): CliPlugin<ModuleTools> => ({
  name: 'my-plugin',

  setup() {
    return {
      afterBuildTask(options: BuildTaskResult): void {
        // ...
      },
    };
  },
});

Parameters and return value types.

export interface BuildTaskResult {
  status: 'success' | 'fail';
  message?: string;
  config: BaseBuildConfig;
}

afterBuild

Triggered after the end of the overall build process.

type: ParallelWorkflow

export const myPlugin = (): CliPlugin<ModuleTools> => ({
  name: 'my-plugin',

  setup() {
    return {
      afterBuild(options: BuildResult): void {
        // ...
      },
    };
  },
});

Parameters and return value types.

export interface BuildResult {
  status: 'success' | 'fail';
  message?: string;
  config: BuildConfig;
  commandOptions: BuildCommandOptions;
  totalDuration: number;
}

buildPlatform hooks

module-tools also provides the build --platform command to perform specific build tasks.

For example, after installing the Module Doc plugin, you can run build --platform or build --platform doc to perform Doc build tasks.

Hooks are triggered in the following order after executing build --platform.

  • registerBuildPlatform
  • beforeBuildPlatform
  • buildPlatform
  • afterBuildPlatform

registerBuildPlatform

Gets information about the tasks that need to be run when executing the build --platform command.

export const myPlugin = (): CliPlugin<ModuleTools> => ({
  name: 'my-plugin',

  setup() {
    return {
      registerBuildPlatform(): RegisterBuildPlatformResult {
        // ...
        return {
          platform: 'doc',
          build() {
            // logic
          },
        }, };
      },
    };
  },
});

Types of parameters entered and returned.

export interface RegisterBuildPlatformResult {
  platform: string | string[];
  build: (
    currentPlatform: string, // the currently running platform build task
    context: { isTsProject: boolean },
  ) => void | Promise<void>;
}

beforeBuildPlatform

Triggers all registered build tasks when the build --platform command is executed. beforeBuildPlatform will be triggered before the execution of the overall build task.

export const myPlugin = (): CliPlugin<ModuleTools> => ({
  name: 'my-plugin',

  setup() {
    return {
      beforeBuildPlatform(platforms: RegisterBuildPlatformResult[]): void {
        console.info(`have ${platforms.length} platform tasks`);
      },
    };
  },
});

Types of parameters entered and returned.

export interface RegisterBuildPlatformResult {
  platform: string | string[];
  build: (
    currentPlatform: string, // the currently running platform build task
    context: { isTsProject: boolean },
  ) => void | Promise<void>;
}

buildPlatform

When the build --platform command is executed, all registered build tasks will be triggered. buildPlatform will be triggered before each build task is executed.

export const myPlugin = (): CliPlugin<ModuleTools> => ({
  name: 'my-plugin',

  setup() {
    return {
      buildPlatform({ platform }: Options): void {
        console.info(`current task is ${platform}`);
      },
    };
  },
});

Types of parameters entered and returned.

export interface Options {
  platform: string;
}

afterBuildPlatform

When the build --platform command is executed, all registered build tasks will be triggered. afterBuildPlatform will be triggered after the overall platform build task is finished.

export const myPlugin = (): CliPlugin<ModuleTools> => ({
  name: 'my-plugin',

  setup() {
    return {
      afterBuildPlatform(result: BuildPlatformResult): void {
        if (result.status === 'success') {
          console.info(`all platform build task success`);
        } else {
          console.error(result.message);
        }
      },
    };
  },
});

Types of parameters entered and returned.

export interface BuildPlatformResult {
  status: 'success' | 'fail';
  message: string | Error | null;
}

Dev Hooks

The following Hooks are triggered in order when the dev command is executed.

  • registerDev: triggered when getting dev function information.
  • beforeDev: Triggered before starting the dev process as a whole.
  • beforeDevMenu: triggered before the dev list/menu appears.
  • afterDevMenu: triggered after dev list/menu option is selected.
  • beforeDevTask: Triggered before executing the dev task.
  • afterDev: Triggered at the end of the overall dev process.

registerDev

Register dev tool related data. Mainly contains.

  • the name of the dev tool
  • The name of the item displayed in the menu list and the corresponding value.
  • The definition of the dev subcommand.
  • Whether to execute the source code build before running the dev task
  • The function to execute the dev task.
export const myPlugin = (): CliPlugin<ModuleTools> => ({
  name: 'my-plugin',

  setup() {
    return {
      registerDev() {
        return {
          // Dev tool name
          name: 'storybook',
          // Menu content
          menuItem: {
            name: 'Storybook',
            value: 'storybook',
          },
          // Defined dev subcommands
          subCommands: ['storybook', 'story'],
          async action() {
            // dev logic
          },
        };
      },
    };
  },
});

Types of parameters entered and returned.

export interface DevToolData {
  name: string;
  subCommands?: string[];
  menuItem?: {
    name: string;
    value: string;
  };
  action: (
    options: { port?: string },
    context: { isTsProject?: boolean },
  ) => void | Promise<void>;
}

beforeDev

Triggered before the dev task is executed after all dev tool metadata has been collected.

export const myPlugin = (): CliPlugin<ModuleTools> => ({
  name: 'my-plugin',

  setup() {
    return {
      beforeDev(metas: DevToolData[]) {
        console.info(`have ${metas.length} dev tools`);
      },
    };
  },
});

Types of parameters entered and returned.

export interface DevToolData {
  name: string;
  subCommands?: string[];
  menuItem?: {
    name: string;
    value: string;
  };
  action: (
    options: { port?: string },
    context: { isTsProject?: boolean },
  ) => void | Promise<void>;
}

(before|after)DevMenu

beforeDevMenu is triggered before the dev list/menu appears. Receives inquirer question as argument. Default value is.

const question = [
  {
    name: 'choiceDevTool',
    message: 'Select dev tool',
    type: 'list',
    // Registered dev messages
    choices,
  },
];

afterDevMenu Triggered after selecting dev list/menu options.

export const myPlugin = (): CliPlugin<ModuleTools> => ({
  name: 'my-plugin',

  setup() {
    return {
      beforeDevMenu(questions) {
        questions[0].message += '!';
        return questions; // required
      },
      afterDevMenu(options: Options) {
        console.info(`choise ${options.result.choiceDevTool} dev tools`);
      },
    };
  },
});

Types of parameters entered and returned.

export type { QuestionCollection } from 'inquirer';

export interface Options {
  result: PromptResult;
  devTools: DevToolData[];
}

export type PromptResult = { choiceDevTool: string };
export interface DevToolData {
  name: string;
  subCommands?: string[];
  menuItem?: {
    name: string;
    value: string;
  };
  action: (
    options: { port?: string },
    context: { isTsProject?: boolean },
  ) => void | Promise<void>;
}

beforeDevTask

Triggered before the dev task is executed.

export const myPlugin = (): CliPlugin<ModuleTools> => ({
  name: 'my-plugin',

  setup() {
    return {
      beforeDevTask(currentDevData: DevToolData) {
        console.info(`${currentDevData.name} running`);
      },
    };
  },
});

Types of parameters entered and returned.

export interface DevToolData {
  name: string;
  subCommands?: string[];
  menuItem?: {
    name: string;
    value: string;
  };
  action: (
    options: { port?: string },
    context: { isTsProject?: boolean },
  ) => void | Promise<void>;
}

afterDev

Triggered when the dev task process is interrupted.

export const myPlugin = (): CliPlugin<ModuleTools> => ({
  name: 'my-plugin',

  setup() {
    return {
      afterDev() {
        console.info(`exit!`);
      },
    };
  },
});