logo
  • Guide
  • Config
  • Plugin
  • API
  • Examples
  • Community
  • Modern.js 2.x Docs
  • English
    • 简体中文
    • English
    • Introduction
      Plugin System
      CLI Plugins
      CLI Plugin API
      Life Cycle
      Runtime Plugins
      Plugin API
      Life Cycle
      Server Plugins
      Plugin API
      Life Cycle
      Official Plugins
      CLI Plugins
      BFF Plugin
      SSG Plugin
      styled-components Plugin
      📝 Edit this page
      Previous pageLife CycleNext pageLife Cycle

      #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.