在nest中,当我们创建一个module, 需要在AppModule里注册才能使用。
src
├── app.controller.spec.ts
├── app.controller.ts
├── app.module.ts
├── app.service.ts
├── main.ts
└── modules
├── user
└── menu
// app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import UserModule from './modules/user/user.module';
import MenuModule from './modules/menu/menu.module';
@Module({
imports: [
UserModule, // 注册UserModule
MenuModule, // 注册MenuModule
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
这样在module多了或者层级复杂的情况下,每次都要手动注册,非常繁琐。
而nest是支持动态导入module的。因此我们可以写一个module的注册工具类,它会将对应目录下的所有module自动注册
// auto-register.util.ts
// 导入path模块的所有内容
import * as path from 'path';
// 导入fs模块的所有内容
import * as fs from 'fs';
// 从@nestjs/common导入DynamicModule, Global, Module
import { DynamicModule, Module, Type } from '@nestjs/common';
// 定义一个接口AutoRegisterOptions,包含一个path属性
export interface AutoRegisterOptions {
path: string;
}
// 定义一个类, 并且@Module装饰器设置为module
@Module({})
export class AutoRegisterModule {
// 静态方法registerModules,接收一个AutoRegisterOptions对象,返回一个DynamicModule对象
static registerModules(options: AutoRegisterOptions): DynamicModule {
// 调用loadModules方法获取模块数组
const modules = this.loadModules(options.path);
// 返回一个包含module和imports属性的对象
return {
module: AutoRegisterModule,
imports: modules,
};
}
// 私有静态方法loadModules,接收一个目录路径,返回模块数组
private static loadModules(directory: string): Type<any>[] {
// 将当前目录与传入目录拼接成完整路径
const normalizedPath = path.join(__dirname, directory);
// 调用loadModulesRecursively方法递归加载模块
return this.loadModulesRecursively(normalizedPath);
}
// 私有静态方法loadModulesRecursively,递归加载模块
private static loadModulesRecursively(directory: string): any[] {
// 读取目录中的文件
const files = fs.readdirSync(directory);
// 使用reduce方法遍历文件,并累加模块数组
return files.reduce((importedModules: Type<any>[], file) => {
// 拼接文件的完整路径
const filePath = path.join(directory, file);
// 检查文件是否是目录
const isDirectory = fs.statSync(filePath).isDirectory();
if (isDirectory) {
// 如果是目录,则递归加载子目录中的模块
importedModules.push(...this.loadModulesRecursively(filePath));
} else if (file.endsWith('.module.js')) {
// 如果是以.module.js结尾的文件,则加载该文件
// eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-require-imports
const module = require(filePath);
// 如果模块存在且有一个默认导出,则将该默认导出添加到模块数组中
if (module && module.default) {
importedModules.push(module.default);
} else {
// 如果没有默认导出,则输出错误信息
console.error(
`Module at ${filePath} does not have a default export.`,
);
}
}
// 返回累加后的模块数组
return importedModules;
}, []);
}
}
然后在AppModule里注册AutoRegisterModule
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { AutoRegisterModule } from './utils/auto-register.util';
@Module({
imports: [
AutoRegisterModule.registerModules({
path: '../modules',
}),
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
重启项目,就会发现所有module都被自动注册了。
注意该方法需要
module是使用export default导出的