【Nest全栈之旅】第九章:创建和组织模块(Module)

Nest提供了一套结构化和模块化的方式来管理应用程序中不同的部分,通过@Module装饰器来声明模块。

从上图中看到,所有应用都会有一个根模块,Nest会从根模块开始收集各个模块之间的依赖关系,形成依赖关系树,在应用初始化时根据依赖关系树实例化不同的模块对象。

创建模块

创建一个nest-module项目

arduino 复制代码
nest n nest-module -p pnpm

默认根模块为AppModule,类装饰器@Module的controllers为注入该模块的控制器集,providers为注入该模块的提供者,它们将在该模块被共享。

imports正是用于导入应用中的其他模块,默认为空,以创建新的User和Order模块为例:

sql 复制代码
nest g resource User --no-spec
nest g resource Order --no-spec

再来看AppModule,UserModule和OrderModule被自动导入到根模块中,成为AppModule的子模块

共享模块

既然有imports,想必也有exports,假设有一个需求,Order模块需要依赖User模块的UserService,那么可以将UserService加入到exports中,使之成为共享服务。此时,Order模块只需导入UserModule即可访问UserService,通过案例来演示一遍:

在User模块中导出User服务

接着在Order模块中导入User模块,此时在Order模块的任何地方,都可以共享User服务

在Order控制器定义路由函数getOrder,再调用orderService中的getOrder方法

在Order服务中通过属性注入User服务依赖,同时调用User服务的getUserHello方法,最终返回一个问候语字符串!

除了属性注入 依赖之外,还可以使用构造函数注入

浏览器中输入访问http://localhost:3000/order,成功返回内容到页面

全局模块

如果有模块被多个地方引用,为了方面,可以使用@Global把它声明为全局模块,这样便可直接注入exports出来的provider,无须再逐个imports

注意使用全局模块前确保你的模块为全局使用,避免导致模块之间的耦合性增加。

动态模块

以上的模块都属于静态模块的绑定和使用,Nest中还提供了动态加载模块的能力,使得应用可以在运行时创建模块,通常用于动态读取配置或根据权限判断来加载模块。基本用法如下:

创建动态模块

typescript 复制代码
// dynamic.module.ts
import { Module, DynamicModule } from '@nestjs/common';
​
@Module({})
export class DynamicModule {
  static forFeature(entities: Function[]): DynamicModule {
    // 在此方法中根据需要创建模块
    return {
      module: DynamicModule,
      providers: [],
      exports: [],
    };
  }
}

在需要使用动态模块的地方,例如某个服务或控制器中,使用 forFeature 方法来动态加载模块

typescript 复制代码
// some.service.ts
import { Injectable } from '@nestjs/common';
import { DynamicModule } from './dynamic.module';
​
@Injectable()
export class SomeService {
  constructor(private readonly dynamicModule: DynamicModule) {}
​
  // 在某个方法中动态加载模块
  loadModule(entities: Function[]) {
    return this.dynamicModule.forFeature(entities);
  }
}

需要动态加载模块时,调用 loadModule 方法即可加载相应模块。

除此之外,还有register和forRoot 方法可用于加载动态模块,register方法通常与外部模块或第三方库集成时使用,它将外部模块动态加载到 Nest.js 模块中。

typescript 复制代码
import { Module } from '@nestjs/common';
import * as someExternalLibrary from 'some-external-library';
​
@Module({})
export class DynamicModule {
  static register(options: SomeOptions) {
    // 在此方法中注册外部模块
    return {
      module: DynamicModule,
      providers: [],
      exports: [],
    };
  }
}

而forRoot 在 Nes中常用于注册根模块。例如用于配置根模块的全局服务或中间件等。

typescript 复制代码
import { Module } from '@nestjs/common';
​
@Module({})
export class CoreModule {
  static forRoot(options: SomeOptions) {
    // 在此方法中配置根模块的全局服务或特性
    return {
      module: CoreModule,
      providers: [],
      exports: [],
    };
  }
}

总结

Nest提供了一套模块化的解决方案,通过@Module来定义模块,模块之间可以通过imports和exports来实现交互和通信,@Global声明为全局模块,但是使用的是需要一定的抽象能力。

还提供了动态加载模块的能力,可以在运行时创建模块,通常用于动态读取配置,如链接数据库配置等,会频繁使用。

Nest的模块就这些概念,掌握之后就明白如何组织功能代码了。

相关推荐
曦樂~9 小时前
【Web Development】03JavaScript 基础和事件
开发语言·前端·javascript
deli0079 小时前
HTTPS 的锁是怎么挂上的?TLS 1.3 握手 6 步实测
前端
程序员大阳9 小时前
副队长ES6+教程(1)--ES6+初识
前端·ecmascript·es6
码云社区10 小时前
智慧物业系统选型指南:房屋档案、账单管理与报修协作
前端·javascript·vue.js·智慧物业
deli00711 小时前
2GB 文件传一半断网实测:HTTP 断点续传只补 15MB
前端
treasure14021 小时前
【复古】浅尝Django前后端不分离
前端·css·python·django·bootstrap·html·web
jay神1 天前
基于 YOLOv8 的手势识别系统(Web 版)
前端·人工智能·python·深度学习·yolo·计算机视觉·计算机毕业设计
屏什么录1 天前
长时间录屏中途崩溃:MP4 打不开的 6 种救回方案与参数设置
前端·音视频开发
code_Bo1 天前
不只命令行:我把跨 Agent 会话同步做成了桌面应用
前端·javascript·后端
kyriewen1 天前
AI 能把页面写出来,为什么改个需求就开始崩?
前端·javascript·人工智能