我需要共享一个动态模块。在文档中我发现我们可以在全球范围内共享服务。 是的,这是一个解决方案。但是,我想知道在模块级别是否可能。这就是为什么我对当动态模块注册几次时会发生什么感兴趣。从实践中,我发现它在 NestJS 中创建了不同的模块实例。 该模块的行为与 Angular 中的不同,但 NestJS 喜欢提及 Angular 的相似性。 属性模块带我走了。现在我明白它仅用于控制模块行为。但是,我没有看到任何 文档中的解释。我看到类似的问题。但我还没有找到我感兴趣的细节。
以下代码只是想法。还没有检查过。
import { DynamicModule, Module } from '@nestjs/common';
import { ConfigService } from './config.service';
@Module({})
export class ConfigModule {
static register(options: Record<string, any>): DynamicModule {
return {
module: ConfigModule,
providers: [
{
provide: 'CONFIG_OPTIONS',
useValue: options,
},
ConfigService,
],
exports: [ConfigService],
};
}
}
export const ConfiguredConfigModule = ConfigModule.register({key: 'flower'});
...
@Module({
imports: [ConfiguredConfigModule]
})
export class AppModule {}
问候。
NestJS 喜欢提及 Angular 相似性。
相似,而不是等同。它们“相似”而不是“相同”。行为上的差异是预料之中的 从实践中,我发现它在 NestJS 中创建了不同的模块实例。
这是正确的。根据convention
,当我们希望制作一次东西并从根模块中重复使用它时,我们使用像
forRoot
这样的名称,当我们希望必须多次注册模块时,我们使用register
这样的名称,但这是onyl社区约定,根本不是一个硬性规则。当您调用
DynamicModule.forRoot/register/Async()
时,您将在当前模块的上下文中创建一个动态模块
如果您想共享动态模块,我建议围绕动态模块创建一个包装器,这样您就可以对
.forRoot()/register()/whaterver()
进行包装器调用,并按名称导出动态模块(添加 exports: [DynamicModule]
)。这将允许您导入包装器并拥有一个 DynamicModule 实例,而无需将其设为全局实例
我在为我的项目创建核心库时遇到了同样的问题。 我还想知道为什么没有信息和方法来共享模块而不使其@Global。在尝试了包装器、全局变量、nestjs 核心反射之后,我找到了使用装饰器的解决方案,该装饰器将动态模块转换为静态模块,不会创建额外的实例并且易于使用。
import { ModuleMetadata, Module, DynamicModule } from '@nestjs/common';
export function SharedModule(metadata: ModuleMetadata): ClassDecorator {
return <T extends Function>(target: T) => {
let isInitialized = false;
Module(metadata)(target);
const getModule = (mdl: DynamicModule) => {
if (isInitialized) {
return target;
}
Module(
mdl
? {
providers: mdl.providers,
exports: mdl.exports,
imports: mdl.imports,
controllers: mdl.controllers,
}
: metadata,
)(target);
isInitialized = true;
};
const staticMethods = Object.getOwnPropertyNames(target).filter(
(prop) => typeof target[prop] === 'function',
);
for (const method of staticMethods) {
const originalMethod = target[method];
target[method] = function (...args: any[]) {
return getModule(originalMethod(...args));
};
}
return target;
};
}
Decorator 完全取代了 @Module(...) 并且到目前为止效果良好。 所有模块导入为 [Module.forRoot()] 或 [Module] 将返回相同的模块实例。
export type StorageModuleOptions = {
clientProvider: Provider<ExtendedCacheClient>;
};
@SharedModule({})
export class StorageModule {
static forRoot(args: StorageModuleOptions): DynamicModule {
const { providers, exports } = buildCustomProvider(args.clientProvider, DICacheClient);
return {
module: StorageModule,
providers: [...providers],
exports: [...exports],
};
}
}