【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的模块就这些概念,掌握之后就明白如何组织功能代码了。

相关推荐
齐 飞2 分钟前
MongoDB笔记01-概念与安装
前端·数据库·笔记·后端·mongodb
神仙别闹19 分钟前
基于tensorflow和flask的本地图片库web图片搜索引擎
前端·flask·tensorflow
aPurpleBerry42 分钟前
JS常用数组方法 reduce filter find forEach
javascript
GIS程序媛—椰子1 小时前
【Vue 全家桶】7、Vue UI组件库(更新中)
前端·vue.js
DogEgg_0011 小时前
前端八股文(一)HTML 持续更新中。。。
前端·html
ZL不懂前端1 小时前
Content Security Policy (CSP)
前端·javascript·面试
乐闻x1 小时前
ESLint 使用教程(一):从零配置 ESLint
javascript·eslint
木舟10091 小时前
ffmpeg重复回听音频流,时长叠加问题
前端
王大锤43912 小时前
golang通用后台管理系统07(后台与若依前端对接)
开发语言·前端·golang
我血条子呢2 小时前
[Vue]防止路由重复跳转
前端·javascript·vue.js