Middleware

Used to extend the built-in Web Server of Modern.js, unlike Hook, Middleware can directly operate Node's origin request and response, and can be extended using the framework plugin.

NOTE

In the next major release, Modern.js will use new middleware to replace this approach.

It is recommended to use UnstableMiddleware to handle page requests.

NOTE

For more detail, see Extend Web Server.

Usage

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

export const middleware: Middleware = async (context, next) => {};
export const middleware: Middleware[] = [
  async (context, next) => {},
  async (context, next) => {},
];
INFO

Before using this API, please execute pnpm run new to create a new "Custom Web Server" source code directory.

pnpm run new
? Please select the operation you want: Create Element
? Please select the type of element to create: New "Custom Web Server" source code directory

Function Signature

type Middleware = (
  context: MiddlewareContext,
  next: NextFunction,
) => Promise<void> | void;

type MiddlewareContext = {
  response: {
    set: (key: string, value: string) => void;
    status: (code: number) => void;
    getStatus: () => number;
    cookies: {
      set: (key: string, value: string, options?: any) => void;
      clear: () => void;
    };
    raw: (
      body: string,
      { status, headers }: { status: number; headers: Record<string, any> },
    ) => void;
    locals: Record<string, any>;
  };
  request: {
    host: string;
    pathname: string;
    query: Record<string, any>;
    cookie: string;
    cookies: {
      get: (key: string) => string;
    };
    headers: IncomingHttpHeaders;
  };
  source: {
    req: IncomingMessage;
    res: ServerResponse;
  };
};

Input

  • context: Middleware context.
    • response: provides a series of methods to process the response.
    • request: provides a series of methods to get request info.
    • source: provides Node.js native req and res object.
  • next: call next listener (not affect the server process, only current hook).
WARNING

The execution of the next function does not affect built-in processes, only controls whether the next middleware executes. Rendering processes are interrupted only when the response is written.

Example

Tracking

export const Middleware = () => async (ctx, next) => {
  const start = Date.now();
  ctx.source.res.once('finish', () => {
    console.log(Date.now() - start);
  });
};

Inject Tools & Data

Modern.js provides res.locals to store local variables for the current request.

export const Middleware = () => async (ctx, next) => {
  ctx.response.locals.id = 'Modern.js';
  ctx.response.locals.rpc = createRpcInstance();
};

Framework Extension

Middleware can also use runtime framework extensions like BFF.

When using framework runtime extensions, type information is exported from @modern-js/runtime/{namespace}. Middleware can use framework syntax, such as framework middleware writing, the following is pseudo-code:

import { SomeType } from '@modern-js/runtime/{namespace}';

export const middleware: SomeType = (ctx, next) => {
  console.log(ctx.url);
  next();
};

By default, the framework extension capability of Web Server is turned off after installing the framework extension plugin. If you want to use the framework extension, you can turn it on through 'server.enableFrameworkExt'.

INFO

The type name exported by the framework extension may not 'Middleware', but is named by the framework extension plugin.