【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 方法即可加载相应模块。

除此之外,还有registerforRoot 方法可用于加载动态模块,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的模块就这些概念,掌握之后就明白如何组织功能代码了。

相关推荐
啊吧啊吧曾小白6 分钟前
作用域、闭包与this指向问题
前端·javascript·面试
Linhieng8 分钟前
浏览器扩展与网页交流
前端
小宁爱Python8 分钟前
CSS的复合选择器
前端·css
今天真是星期八10 分钟前
AI 时代如何正确选择前端框架:React、Angular 还是 Vue?
前端
yaoganjili13 分钟前
WebGL打开 3D 世界的大门(六):透视投影
前端·数据可视化
HiF14 分钟前
Hexo博客集成LivePhoto
javascript
ChasLui16 分钟前
[译]在公共领域构建一个速度极快的缓冲数据网格。
前端·neo
八了个戒27 分钟前
「数据可视化 D3系列」入门第七章:坐标轴的使用
前端·javascript·数据可视化·canvas·d3
NON-JUDGMENTAL29 分钟前
HTML:网页的骨架 — 入门详解教程
前端·html
muyouking1131 分钟前
0.深入探秘 Rust Web 框架 Axum
开发语言·前端·rust