插件

使用运行时插件扩展 Nitro 的运行时行为。

运行时插件会在服务器启动期间执行一次,因此它们适合用于一次性初始化以及注册生命周期钩子。每个插件都会接收 nitroApp 上下文。

插件会从 plugins/ 目录自动注册并同步运行。插件函数本身必须是同步的(返回 void),但它们注册的钩子可以是异步的。

plugins/test.ts
import { definePlugin } from "nitro";

export default definePlugin((nitroApp) => {
  console.log('Nitro plugin', nitroApp)
})

如果你有其他目录中的插件,可以使用 plugins 选项:

nitro.config.ts
import { defineConfig } from "nitro";

export default defineConfig({
  plugins: ['my-plugins/hello.ts']
})

插件按以下顺序运行:

按 plugins 选项中列出的顺序运行其中列出的插件。
运行从 plugins/ 目录自动注册的插件。目录按照 scanDirs 的顺序处理,每个目录中的文件则按路径排序。

#nitroApp 上下文

插件函数接收一个具有以下属性的 nitroApp 对象:

属性类型描述
hooksHookableCore用于注册生命周期回调的钩子系统。
h3H3Core底层的 H3 应用实例。
fetch(req: Request) => Response | Promise<Response>应用的内部 fetch 处理器。
captureError(error: Error, context) => void以编程方式将错误捕获到错误钩子管道中。

Note

H3 会在第一个请求时组合一次中间件链。插件在启动期间添加到 nitroApp.h3["~middleware"] 的中间件会被包含在内,但如果它们位于数组前部,则会在 Nitro 的路由规则之前运行。如果插件在处理第一个请求后修改了该数组,则还必须将 nitroApp.h3["~dispatch"] 和 nitroApp.h3["~composed"] 重置为 undefined,以便重新组合该链。

#Nitro 运行时钩子

使用 Nitro 钩子 在请求生命周期中的特定时间点运行自定义函数。在插件内部使用 nitroApp.hooks.hook() 注册它们:

plugins/close.ts
import { definePlugin } from "nitro";

export default definePlugin((nitroApp) => {
  nitroApp.hooks.hook("close", async () => {
    // 当 nitro 关闭时运行
  });
})

#可用的钩子

钩子签名描述
request(event: HTTPEvent) => void | Promise<void>在每个请求开始时调用。
response(res: Response, event: HTTPEvent) => void | Promise<void>在响应创建后调用。
error(error: Error, context: { event?: HTTPEvent, tags?: string[] }) => void当错误被捕获时调用。
close() => void当 Nitro 服务器关闭时调用。

Note

NitroRuntimeHooks 接口是可扩展的。部署预设(如 Cloudflare)可以使用平台特定的钩子(如 cloudflare:scheduled 和 cloudflare:email)来扩展它。

#注销钩子

hook() 方法返回一个注销函数,可以调用该函数来移除钩子:

plugins/example.ts
import { definePlugin } from "nitro";

export default definePlugin((nitroApp) => {
  const unregister = nitroApp.hooks.hook("request", (event) => {
    // ......
  });

  // 稍后,移除该钩子
  unregister();
});

#示例

#捕获错误

你可以使用插件来捕获所有应用错误。

plugins/errors.ts
import { definePlugin } from "nitro";

export default definePlugin((nitroApp) => {
  nitroApp.hooks.hook("error", async (error, { event }) => {
    console.error(`${event?.req.url} Application error:`, error)
  });
})

context 对象包含一个可选的 tags 数组,用于标识错误来源(例如 "request"、"response"、"cache"、"plugin"、"unhandledRejection"、"uncaughtException")。

#以编程方式捕获错误

你可以使用 captureError 手动将错误送入错误钩子管道:

plugins/capture.ts
import { definePlugin } from "nitro";

export default definePlugin((nitroApp) => {
  nitroApp.captureError(new Error("something went wrong"), {
    tags: ["startup"],
  });
});

#优雅关闭

服务器会优雅地关闭,等待所有使用 event.waitUntil 启动的待处理后台任务。使用 close 钩子清理你自己的资源:

plugins/shutdown.ts
import { definePlugin } from "nitro";

export default definePlugin((nitroApp) => {
  nitroApp.hooks.hook("close", async () => {
    // 清理资源、关闭连接等。
  });
});

#请求和响应生命周期

你可以使用插件注册在请求生命周期中运行的钩子:

plugins/lifecycle.ts
import { definePlugin } from "nitro";

export default definePlugin((nitroApp) => {
  nitroApp.hooks.hook("request", (event) => {
    console.log("on request", event.req.url);
  });

  nitroApp.hooks.hook("response", (res, event) => {
    // 修改或检查响应
    console.log("on response", res.status);
  });
});

#修改响应头

plugins/headers.ts
import { definePlugin } from "nitro";

export default definePlugin((nitroApp) => {
  nitroApp.hooks.hook("response", (res, event) => {
    const { pathname } = new URL(event.req.url);
    if (pathname.endsWith(".css") || pathname.endsWith(".js")) {
      res.headers.append("Vary", "Origin");
    }
  });
});