Skip to content

概述

提示

本章介绍的是 Nest Devtools 与 Nest 框架的集成方式。如果你要访问 Devtools 应用本身,请前往 Devtools 网站。

要开始调试本地应用,请打开 main.ts,并确保在应用选项对象中将 snapshot 设置为 true

typescript
async function bootstrap() {
  const app = await NestFactory.create(AppModule, {
    snapshot: true,
  });
  await app.listen(process.env.PORT ?? 3000);
}

这会告诉框架收集必要的元数据,以便 Nest Devtools 将你的应用图可视化出来。

接下来安装所需依赖:

bash
$ npm i @nestjs/devtools-integration

警告

如果你的应用使用了 @nestjs/graphql,请确保安装的是最新版本(npm i @nestjs/graphql@11)。

安装完成后,打开 app.module.ts,并导入刚刚安装的 DevtoolsModule

typescript
@Module({
  imports: [
    DevtoolsModule.register({
      http: process.env.NODE_ENV !== 'production',
    }),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

警告

这里检查 NODE_ENV 的原因是:你绝不应该在生产环境中使用这个模块。

导入 DevtoolsModule 并启动应用(npm run start:dev)后,你就可以访问 Devtools 并看到应用的内省图。

提示

从上面的截图可以看到,每个模块都会连接到 InternalCoreModuleInternalCoreModule 是一个全局模块,始终会被导入根模块。由于它被注册为全局节点,Nest 会自动在所有模块与 InternalCoreModule 节点之间创建边。如果你想在图中隐藏全局模块,可以勾选侧边栏里的 “Hide global modules” 复选框。

也就是说,DevtoolsModule 会让你的应用额外暴露一个 HTTP 服务器(默认监听在 8000 端口),Devtools 应用会通过它来内省你的应用。

为了确认一切工作正常,把图视图切换为 “Classes”。你应该会看到类似下图:

如果你想聚焦某个特定节点,点击对应矩形后,图中会弹出一个包含 “Focus” 按钮的窗口。你也可以使用侧边栏中的搜索框来查找节点。

提示

点击 Inspect 按钮后,应用会跳转到 /debug 页面,并自动选中当前节点。

提示

如果你想把图导出为图片,可以点击图右上角的 Export as PNG 按钮。

利用左侧边栏中的表单控件,你还可以控制边的邻近范围,以便只可视化某个局部应用子树:

当团队里有新成员时,这个能力尤其有用,因为你可以快速向他们展示应用结构。它同样适合在拆分大型应用时使用,例如你可以专门查看某个模块(如 TasksModule)及其全部依赖,这在把单体应用拆分为更小模块甚至独立微服务时很有帮助。

你可以观看下面这个视频,了解 Graph Explorer 功能的实际效果:

排查 “Cannot resolve dependency” 错误

注意

该功能要求 @nestjs/core 版本不低于 v9.3.10

最常见的一类错误之一,就是 Nest 无法解析某个 provider 的依赖。借助 Nest Devtools,你可以非常轻松地识别问题并了解修复方式。

首先,打开 main.ts,把 bootstrap() 的调用改成下面这样:

typescript
bootstrap().catch((err) => {
  fs.writeFileSync('graph.json', PartialGraphHost.toString() ?? '');
  process.exit(1);
});

同时,确保把 abortOnError 设置为 false

typescript
const app = await NestFactory.create(AppModule, {
  snapshot: true,
  abortOnError: false, // <--- 这里
});

这样一来,只要应用因 “Cannot resolve dependency” 错误而启动失败,就会在项目根目录下生成一个 graph.json(表示部分图)。然后你可以把这个文件拖放到 Devtools 中(记得先把当前模式从 “Interactive” 切换成 “Preview”):

上传成功后,你会看到如下图和对话框:

可以看到,被高亮的 TasksModule 就是我们应优先排查的模块。而在右侧对话框里,通常也已经给出了修复建议。

如果切换到 “Classes” 视图,则会看到:

这张图说明:我们希望注入到 TasksServiceDiagnosticsService,在 TasksModule 的上下文中没有找到。也就是说,修复方式很可能只是把 DiagnosticsModule 导入到 TasksModule 中。

路由浏览器

当你进入 Routes explorer 页面时,你会看到所有已注册的入口点:

提示

这里展示的不仅仅是 HTTP 路由,还包括其他所有入口点,例如 WebSockets、gRPC、GraphQL resolver 等。

这些入口点会按宿主 controller 分组显示。你也可以使用搜索框快速定位某个入口点。

点击某个具体入口点后,会展示一张流图。这张图会显示该入口点的执行流程,例如绑定到这条路由上的 guards、interceptors、pipes 等。当你想理解某条路由的请求 / 响应链路,或在排查为什么某个 guard / interceptor / pipe 没有被执行时,这个功能尤其有用。

Sandbox

如果你想实时执行 JavaScript 代码,并即时与应用交互,可以进入 Sandbox 页面:

这个 playground 可以用来实时测试和调试 API 端点,让开发者无需借助额外的 HTTP 客户端,就能快速定位并修复问题。你甚至还可以绕过认证层,因此不再需要额外登录,甚至不需要专门为测试准备用户账号。对于事件驱动型应用,你也可以直接在 playground 里触发事件,并观察应用如何响应。

所有日志都会被收集并输出到 playground 的控制台,因此你可以非常直观地看到当前发生了什么。

你只需要即时执行代码,就能立刻看到结果,而无需重新构建应用、重启服务器。

提示

如果你想更好地展示对象数组,可以使用 console.table()(或者简写成 table())。

你也可以观看下面这段视频,看看 Interactive Playground 的实际效果:

启动性能分析器

如果你想查看所有类节点(controller、provider、enhancer 等)及其对应的实例化耗时,可以进入 Bootstrap performance 页面:

当你想识别应用启动过程中最慢的部分时,这个页面会特别有帮助。例如,在 serverless 场景中,优化启动时间往往非常关键。

审计

如果你想查看应用在分析序列化图时自动生成的审计结果(错误 / 警告 / 提示),可以进入 Audit 页面:

提示

上面的截图没有展示全部可用的审计规则。

这个页面非常适合用于识别应用中潜在的问题。

预览静态文件

如果你想把序列化图保存到文件,可以使用下面这段代码:

typescript
await app.listen(process.env.PORT ?? 3000); // 或者 await app.init()
fs.writeFileSync('./graph.json', app.get(SerializedGraph).toString());

提示

SerializedGraph@nestjs/core 包导出。

随后,你就可以把这个文件拖放 / 上传到 Devtools:

这在你想把图分享给其他人(例如同事),或者想离线分析图结构时非常有用。

基于 NestJS 官方文档翻译