Plugin API

Modern.js's Server plugins allow you to extend and customize functionality during the server-side request processing phase, such as adding middleware, modifying request responses, etc.

Info

Server plugins need to be configured via the plugins field in server/modern.server.ts.

Plugin Basic Structure

A typical Server plugin structure is as follows:

import type { ServerPlugin } from '@modern-js/server-runtime';

const myServerPlugin = (): ServerPlugin => ({
  name: '@my-org/my-server-plugin', // Plugin name, ensure uniqueness
  setup: api => {
    // Use the API here to register hooks, add middleware, etc.
    api.onPrepare(() => {
      const { middlewares } = api.getServerContext();
      middlewares?.push({
        name: 'my-middleware',
        handler: async (c, next) => {
          console.log('Processing request...');
          await next();
        },
      });
    });
  },
});

export default myServerPlugin;
  • name: A unique identifier for the plugin.
  • The setup function receives an api object, which provides all available Server plugin APIs.

Information Retrieval

api.getServerContext

Gets the context information of the Modern.js server.

  • Returns: A ServerContext object containing the following fields:
Field NameTypeDescription
middlewaresMiddlewareObj[]Middleware list
renderMiddlewaresMiddlewareObj[]Render middleware list
routesServerRoute[]Server routing information
appDirectorystringAbsolute path to the project root
apiDirectorystringAbsolute path to the API module dir
lambdaDirectorystringAbsolute path to the Lambda module dir
sharedDirectorystringAbsolute path to the shared module dir
distDirectorystringAbsolute path to the output directory
pluginsServerPlugin[]List of currently registered plugins
  • Example:
api.onPrepare(() => {
  const serverContext = api.getServerContext();
  console.log(`App directory: ${serverContext.appDirectory}`);
  console.log(`${serverContext.plugins.length} plugins registered`);
});
Info

The context information returned by getServerContext is read-only. Use updateServerContext if you need to modify it.


api.getServerConfig

Gets the server configuration defined by the user in the server/modern.server.ts file.

  • Returns: The user-defined server configuration object.
  • Example:
api.onPrepare(() => {
  const serverConfig = api.getServerConfig();
  if (serverConfig.middlewares) {
    console.log('User has customized middleware configuration');
  }
});

api.getHooks

Gets all registered hook functions.

  • Returns: An object containing all hook functions.
  • Example:
const hooks = api.getHooks();
// Manually trigger the onPrepare hook
await hooks.onPrepare.call();
Warning

In custom plugins, you can only manually call the hooks registered by the corresponding plugin and cannot call official hooks to avoid affecting the normal execution order of the application.


Context Modification

api.updateServerContext

Updates the server context information.

  • Type: api.updateServerContext(updateContext: DeepPartial<ServerContext>)
  • Parameters:
    • updateContext: The context object to update (partial update).
  • Execution Phase: Can be used at any stage.
  • Example:
api.onPrepare(() => {
  const context = api.getServerContext();
  api.updateServerContext({
    middlewares: [
      ...context.middlewares,
      {
        name: 'new-middleware',
        handler: async (c, next) => {
          await next();
        },
      },
    ],
  });
});

Lifecycle Hooks

api.onPrepare

Adds additional logic during the server preparation phase.

  • Type: api.onPrepare(prepareFn: () => void | Promise<void>)
  • Parameters:
    • prepareFn: A preparation function, without parameters, can be asynchronous.
  • Execution Phase: After the server completes configuration validation and before applying middleware.
  • Example:
api.onPrepare(async () => {
  const { middlewares } = api.getServerContext();

  // Add custom middleware
  middlewares.push({
    name: 'request-logger',
    handler: async (c, next) => {
      const start = Date.now();
      await next();
      const duration = Date.now() - start;
      console.log(`Request duration: ${duration}ms`);
    },
  });
});
Info

In the onPrepare hook, you can modify the context object returned by getServerContext() (such as middlewares, renderMiddlewares), and these modifications will take effect when the server starts.


api.onReset

Adds additional logic when the server resets.

  • Type: api.onReset(resetFn: (params: { event: ResetEvent }) => void | Promise<void>)
  • Parameters:
    • resetFn: A reset handler function that receives reset event parameters.
      • event.type: Event type, possible values:
        • 'repack': Repack event
        • 'file-change': File change event
      • event.payload: When type is 'file-change', contains an array of file change information.
  • Execution Phase: When files change or repack is needed.
  • Example:
api.onReset(async ({ event }) => {
  if (event.type === 'file-change') {
    console.log('File changes detected:', event.payload);
    // Perform cleanup or re-initialization operations
  } else if (event.type === 'repack') {
  }
});

Other Notes

  • Refer to Server Plugin Lifecycle to understand the execution order of plugin hooks.
  • The execution order of middleware can be controlled through the order field ('pre', 'default', 'post'), or through the before field to specify execution before other middleware.