---
title: Hook List
sidebar_position: 8
---

# Hook List

Modern.js exposes three types of plugins: CLI, Runtime, and Server.

## CLI

### `beforeConfig`

- Functionality: Running tasks before the config process
- Execution phase: Before the config process
- Hook model: AsyncWorkflow
- Type: `AsyncWorkflow<void, void>`
- Example usage:

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

export default (): CliPlugin => ({
  setup(api) {
    return {
      beforeConfig: () => {
        // do something
      },
    };
  },
});
```

### `config`

- Functionality: Collect configuration
- Execution phase: After parsing the configuration in `modern.config.ts`
- Hook model: ParallelWorkflow
- Type: `ParallelWorkflow<void, unknown>`
- Example usage:

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

export default (): CliPlugin => ({
  setup(api) {
    return {
      config: () => {
        return {
          /** some config */
        };
      },
    };
  },
});
```

The collected configuration information will be collected and processed uniformly.

### `validateSchema`

- Functionality: Collect the JSON schema used to validate user configurations in various plugins.
- Execution phase: After the `config` Hook has run.
- Hook model: ParallelWorkflow
- Type: `ParallelWorkflow<void, unknown>`
- Example usage:

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

export default (): CliPlugin => ({
  setup(api) {
    return {
      validateSchema: () => {
        return {
          // target is field
          target: 'foo',
          schema: {
            type: 'string',
          },
        };
      },
    };
  },
});
```

The returned JSON Schema here is used to validate the configuration information in `modern.config.js`.

For example, the following JSON Schema is returned:

```json
{
  "target": "foo",
  "schema": {
    "type": "string"
  }
}
```

You can configure it in `modern.config.ts` like this:

```ts title="modern.config.ts"
export default defineConfig({
  foo: 'test',
});
```

If it is another type, validation will fail and an error will be reported. For example:

```ts title="modern.config.ts"
export default defineConfig({
  foo: {},
});
```

then throw error:

```sh
$ modern dev
  1 | {
> 2 |   "foo": {},
    |   ^^^^^  Property foo is not expected to be here
```

### `prepare`

- Functionality: Preparatory process for running the main process.
- Execution phase: After configuration validation.
- Hook model: AsyncWorkflow
- Type: `AsyncWorkflow<void, void>`
- Example usage:

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

export default (): CliPlugin => ({
  setup(api) {
    return {
      prepare: () => {
        // do something
      },
    };
  },
});
```

### `afterPrepare`

- function: Running tasks after the prepare process
- Execution Phase: After the prepare process
- Hook model: AsyncWorkflow
- type: `AsyncWorkflow<void, void>`
- Usage:

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

export default (): CliPlugin => ({
  setup(api) {
    return {
      afterPrepare: () => {
        // do something
      },
    };
  },
});
```

### `commands`

- Functionality: Add new commands for the command.
- Execution phase: After the `prepare` Hook has run.
- Hook model: AsyncWorkflow
- Type: `AsyncWorkflow<{ program: Command; }, void>`
- Example usage:

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

export default (): CliPlugin => ({
  setup(api) {
    return {
      commands: ({ program }) => {
        program.command('foo').action(async () => {
          // do something
          console.log('foo');
        });
      },
    };
  },
});
```

Move the plugin to `modern.config.ts`:

```ts title="modern.config.ts"
import myPlugin from './config/plugin/myPlugin';

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

run `modern foo`:

```sh
$ modern foo
foo
```

### `beforeExit`

- Functionality: Reset some file states before exiting the process.
- Execution phase: Before the process exits.
- Hook model: Workflow
- Type: `Workflow<void, void>`
- Example usage:

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

export default (): CliPlugin => ({
  setup(api) {
    return {
      beforeExit: () => {
        // do something
      },
    };
  },
});
```

:::tip
Since the callback function when exiting the process in Node.js is synchronous, the type of `beforeExit` Hook is `Workflow` and cannot perform asynchronous operations.
:::

### `beforeDev`

- Functionality: Tasks before running the main dev process.
- Execution phase: Before the project starts when the `dev` command is run.
- Hook model: AsyncWorkflow
- Type: `AsyncWorkflow<void, unknown>`
- Example usage:

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

export default (): CliPlugin => ({
  setup(api) {
    return {
      beforeDev: () => {
        // do something
      },
    };
  },
});
```

### `afterDev`

- Function: Tasks to be executed after the main process of `dev` command
- Execution Stage: It is executed after each compilation is completed when running the `dev` command
- Hook Model: AsyncWorkflow
- Type: `AsyncWorkflow<{ isFirstCompile: boolean }, unknown>`
- Usage Example:

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

export default (): CliPlugin => ({
  setup(api) {
    return {
      afterDev: () => {
        // do something
      },
    };
  },
});
```

`afterDev` will be executed after each compilation is completed, you can use the `isFirstCompile` param to determine whether it is the first compilation:

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

export default (): CliPlugin => ({
  setup(api) {
    return {
      afterDev: ({ isFirstCompile }) => {
        if (isFirstCompile) {
          // do something
        }
      },
    };
  },
});
```

### `beforeCreateCompiler`

- Function: Provides access to the Webpack configuration used to create the Webpack Compiler within middleware functions.
- Execution Stage: Executed before creating the Webpack Compiler.
- Hook Model: AsyncWorkflow.
- Type: `AsyncWorkflow<{ webpackConfigs: Configuration[];}, unknown>`.
- Usage Example:

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

export default (): CliPlugin => ({
  setup(api) {
    return {
      beforeCreateCompiler: ({ webpackConfigs }) => {
        // do something
      },
    };
  },
});
```

### `afterCreateCompiler`

- Function: Provides access to the created Webpack Compiler within middleware functions.
- Execution Stage: Executed after creating the Webpack Compiler.
- Hook Model: AsyncWorkflow.
- Type: `AsyncWorkflow<{ compiler: Compiler | MultiCompiler | undefined; }, unknown>`.
- Usage Example:

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

export default (): CliPlugin => ({
  setup(api) {
    return {
      afterCreateCompiler: ({ compiler }) => {
        // do something
      },
    };
  },
});
```

### `beforePrintInstructions`

- Function: Provides access to the log information that will be printed within middleware functions and allows modification of the log information.
- Execution Stage: Executed before printing the log information.
- Hook Model: AsyncWaterfall.
- Type: `AsyncWaterfall<{ instructions: string }>`
- Usage Example:

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

export default (): CliPlugin => ({
  setup(api) {
    return {
      beforePrintInstructions: ({ instructions }) => {
        // do something
        return {
          instructions: [...instructions, 'some new message'],
        };
      },
    };
  },
});
```

### `beforeBuild`

- Function: Tasks to be executed before the main process of the `build` command, provides access to the Webpack configuration used for building.
- Execution Stage: Executed before starting the project build when running the `build` command.
- Hook Model: AsyncWorkflow.
- Type: `AsyncWorkflow<{ webpackConfigs: Configuration[]; }>`.
- Usage Example:

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

export default (): CliPlugin => ({
  setup(api) {
    return {
      beforeBuild: () => {
        // do something
      },
    };
  },
});
```

### `afterBuild`

- Function: Tasks to be executed after the main process of the `build` command.
- Execution Stage: Executed after the project build is completed when running the `build` command.
- Hook Model: AsyncWorkflow.
- Type: `AsyncWorkflow<void, unknown>`.
- Usage Example:

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

export default (): CliPlugin => ({
  setup(api) {
    return {
      afterBuild: () => {
        // do something
      },
    };
  },
});
```

### `modifyEntryImports`

- Function: Used for modifying or adding `import` statements in the generated entry files.
- Execution Stage: Executed before generating the entry files, triggered during the [`prepare`](#prepare) stage.
- Hook Model: AsyncWaterfall.
- Type: `AsyncWaterfall<{ imports: ImportStatement[]; entrypoint: Entrypoint; }>`
- Usage Example:

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

export default (): CliPlugin => ({
  setup(api) {
    return {
      modifyEntryImports({ entrypoint, imports }) {
        // add `import React from 'React'`
        imports.push({
          value: 'react',
          specifiers: [
            {
              imported: 'unmountComponentAtNode',
            },
          ],
        });

        return { entrypoint, imports };
      },
    };
  },
});
```

### `modifyEntryExport`

- Function: used to modify the `export` statement in the generated entry file
- Execution Stage: Before the entry file is generated, the [`prepare`](#prepare) phase triggers
- Hook Model: AsyncWaterfall
- Type: `AsyncWaterfall<{ entrypoint: Entrypoint; exportStatement: string; }>`
- Example of use:

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

export default (): CliPlugin => ({
  setup(api) {
    return {
      modifyEntryExport({ entrypoint, exportStatement }) {
        return {
          entrypoint,
          exportStatement: [`export const foo = 'test'`, exportStatement].join(
            '\n',
          ),
        };
      },
    };
  },
});
```

### `modifyEntryRuntimePlugins`

- Function: Used for adding or modifying [Runtime plugins](#Runtime) in the generated entry files.
- Execution Stage: Executed before generating the entry files, triggered during the [`prepare`](#prepare) stage.
- Hook Model: AsyncWaterfall.
- Type: `AsyncWaterfall<{ entrypoint: Entrypoint; plugins: RuntimePlugin[]; }>`
- Usage Example:

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

export default (): CliPlugin => ({
  setup(api) {
    return {
      modifyEntryRuntimePlugins({ entrypoint, plugins }) {
        const name = 'customPlugin';
        const options = {
          /** serializable content */
        };

        return {
          plugins: [
            ...plugins,
            {
              name,
              options: JSON.stringify(options),
            },
          ],
        };
      },
    };
  },
});
```

### `modifyEntryRenderFunction`

- Function: Used for modifying the `render` function in the generated entry files.
- Execution Stage: Executed before generating the entry files, triggered during the [`prepare`](#prepare) stage.
- Hook Model: AsyncWaterfall.
- Type: `AsyncWaterfall<{ entrypoint: Entrypoint; code: string; }>`
- Usage Example:

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

export default (): CliPlugin => ({
  setup(api) {
    return {
      modifyEntryRenderFunction({ entrypoint, code }) {
        const customRender = `/** render function body */`;
        return {
          entrypoint,
          code: customRender,
        };
      },
    };
  },
});
```

### `modifyFileSystemRoutes`

- Function: Used for modifying the content of the generated front-end page routing files, which must be serializable.
- Execution Stage: Executed before generating the front-end routing files, triggered during the [`prepare`](#prepare) stage.
- Hook Model: AsyncWaterfall.
- Type: `AsyncWaterfall<{ entrypoint: Entrypoint; routes: Route[]; }>`
- Usage Example:

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

export default (): CliPlugin => ({
  setup(api) {
    return {
      modifyFileSystemRoutes({ entrypoint, routes }) {
        return {
          entrypoint,
          routes: [
            ...routes,
            {
              path: '/custom_page',
              component: require.resolve('./Component'),
              exact: true,
            },
          ],
        };
      },
    };
  },
});
```

This adds a new page route for the front-end.

### `modifyServerRoutes`

- Function: Used for modifying the content of the generated server routes.
- Execution Stage: Executed before generating the server routing files, triggered during the [`prepare`](#prepare) stage.
- Hook Model: AsyncWaterfall.
- Type: `AsyncWaterfall<{ routes: ServerRoute[]; }>`
- Usage Example:

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

export default (): CliPlugin => ({
  setup(api) {
    return {
      modifyServerRoutes({ routes }) {
        return {
          routes: [
            ...routes,
            {
              urlPath: '/api/foo',
              isApi: true,
              entryPath: '',
              isSPA: false,
              isSSR: false,
            },
          ],
        };
      },
    };
  },
});
```

### `modifyAsyncEntry`

- Function: Used for modifying the asynchronous module that wraps the entry file, see [source.enableAsyncEntry](/configure/app/source/enable-async-entry).
- Execution Stage: Executed before generating the entry files, triggered during the [`prepare`](#prepare) stage.
- Hook Model: AsyncWaterfall.
- Type: `AsyncWaterfall<{ entrypoint: Entrypoint; code: string; }>`
- Usage Example:

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

export default (): CliPlugin => ({
  setup(api) {
    return {
      modifyAsyncEntry({ entrypoint, code }) {
        const customCode = `console.log('hello');`;
        return {
          entrypoint,
          code: `${customCode}${code}`,
        };
      },
    };
  },
});
```

### `htmlPartials`

- Function: Used for customizing the generated HTML page template.
- Execution Stage: Triggered during the [`prepare`](#prepare) stage.
- Hook Model: AsyncWaterfall.
- Type: `AsyncWaterfall<{ entrypoint: Entrypoint; partials: HtmlPartials; }>`
- Usage Example:

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

export default (): CliPlugin => ({
  setup(api) {
    return {
      async htmlPartials({ entrypoint, partials }) {
        partials.head.push('<script>console.log("test")</script>');
        return {
          entrypoint,
          partials,
        };
      },
    };
  },
});
```

This adds a new Script tag to the HTML template.

{/* ## Server

:::note
The Server plugin is currently not fully opened, and the API is not guaranteed to be stable. Use with caution.
:::

Plugins are also supported in the Server section of the application project. The hook will provide hooks for specific stage calls and special functionality.

### `create`

- Function: In the middleware function, you will get the measurement tool configuration `measureOptions` and log tool configuration `loggerOptions` used for Server initialization, and return a custom measurement tool `measure` and log tool configuration `logger`.
- Execution Stage: Server initialization.
- Hook Model: AsyncPipeline.
- Type: `AsyncPipeline<ServerInitInput, InitExtension>`
- Usage Example:

```ts
import type { ServerPlugin } from '@modern-js/server-core';

export default (): ServerPlugin => ({
  setup(api) {
    return {
      create: ({ measureOptions, loggerOptions }) => {
        // do something
      },
    };
  },
});
```

### `prepareWebServer`

- Function: Sets the handling function for the Web route. In the middleware function, you can get the front-end middleware of the Web server.
- Execution Stage: When the request arrives.
- Hook Model: AsyncPipeline.
- Type: `AsyncPipeline<WebServerStartInput, Adapter>`
- Usage Example:

```ts
import type { ServerPlugin } from '@modern-js/server-core';

export default (): ServerPlugin => ({
  setup(api) {
    return {
      prepareWebServer: ({ middleware }) => {
        // do something

        return (req, res) => {
          // do response
        };
      },
    };
  },
});
```

### `prepareApiServer`

- Function: Sets the handling function for the API route. In the middleware function, you can get the front-end middleware of the API server.
- Execution Stage: When the request arrives and matches the BFF basename.
- Hook Model: AsyncPipeline.
- Type: `AsyncPipeline<APIServerStartInput, Adapter>`
- Usage Example:

```ts
import type { ServerPlugin } from '@modern-js/server-core';

export default (): ServerPlugin => ({
  setup(api) {
    return {
      prepareApiServer: ({ middleware }) => {
        // do something

        return (req, res) => {
          // do response
        };
      },
    };
  },
});
```*/}

## Runtime

:::note
The Runtime plugin is currently not fully opened, and the API is not guaranteed to be stable. Use with caution.
:::

The Runtime plugin is mainly used for developers to modify the component that need to be rendered.

### `init`

- Function: Executes `App.init`.
- Execution Stage: Rendering (SSR/CSR).
- Hook Model: AsyncPipeline.
- Type: `AsyncPipeline<{ context: RuntimeContext; }, unknown>`
- Usage Example:

```ts
import type { Plugin } from '@modern-js/runtime';

export default (): Plugin => ({
  setup(api) {
    return {
      init({ context }, next) {
        // do something
        return next({ context });
      },
    };
  },
});
```

### `hoc`

- Function: Modifies the components that need to be rendered.
- Execution Stage: Rendering (SSR/CSR).
- Hook Model: Pipeline.
- Type: `Pipeline<{ App: React.ComponentType<any>; }, React.ComponentType<any>>`
- Usage Example:

:::note
When using the hoc hook, you need to copy the static properties of the original App component to the new component and pass through the props.
:::

```ts
import { createContext } from 'react';
import type { Plugin } from '@modern-js/runtime';
import hoistNonReactStatics from 'hoist-non-react-statics';

export default (): Plugin => ({
  setup(api) {
    const FooContext = createContext('');
    return {
      hoc({ App }, next) {
        const AppWrapper = (props: any) => {
          return (
            <FooContext.Provider store={'test'}>
              <App {...props} />
            </FooContext.Provider>
          );
        };
        return next({
          App: hoistNonReactStatics(AppWrapper, App),
        });
      },
    };
  },
});
```

{/* ### `provide`

- Function: Modifies the Elements that need to be rendered.
- Execution Stage: Rendering (SSR/CSR).
- Hook Model: Pipeline.
- Type: `Pipeline<{ element: JSX.Element; props: AppProps; context: RuntimeContext }, JSX.Element>`
- Usage Example:

```ts
import { createContext } from 'react';
import type { Plugin } from '@modern-js/runtime';

export default (): Plugin => ({
  setup(api) {
    const FooContext = createContext('');

    return {
      provide: ({ element }) => <div>{element}</div>,
    };
  },
});
```

### `client`

- Function: Customizes the client-side rendering process.
- Execution Stage: Client-side rendering in the browser.
- Hook Model: AsyncPipeline.
- Type: `AsyncPipeline<{ App: React.ComponentType<any>; context?: RuntimeContext; rootElement: HTMLElement; }, void>`
- Usage Example:

```ts
import ReactDOM from 'react-dom';
import type { Plugin } from '@modern-js/runtime';

export default (): Plugin => ({
  setup(api) {
    return {
      client: async ({ App, rootElement }) => {
        ReactDOM.render(
          React.createElement(App, { context: { foo: 'test' } }),
          rootElement,
        );
      },
    };
  },
});
```

### `server`

- Function: Customize the server-side rendering process.
- Execution Phase: SSR
- Hook Model: AsyncPipeline
- Type: `AsyncPipeline<{ App: React.ComponentType<any>; context?: RuntimeContext; }, string>`
- Usage Example:

```ts
import ReactDomServer from 'react-dom/server';
import type { Plugin } from '@modern-js/runtime';

export default (): Plugin => ({
  setup(api) {
    return {
      server({ App, context }) {
        return ReactDomServer.renderToString(
          React.createElement(App, { context: { foo: 'test' } }),
        );
      },
    };
  },
});
``` */}
