当前位置: 首页 > news >正文

网站标题优化黄冈网站推广厂家

网站标题优化,黄冈网站推广厂家,无锡做网站公司哪家好,重庆搜索引擎优化Nest Dynamic modules 文档地址👈 记录Dynamic modules是因为确实抽象,文档并没有很详细的指出不同方式创建动态模块的区别 两种不同的动态模块创建方式 静态模块传统动态模块方式实现三种不同的方法命名使用ConfigurableModuleBuilder异步动态模块如果…

Nest Dynamic modules 文档地址👈

记录Dynamic modules是因为确实抽象,文档并没有很详细的指出不同方式创建动态模块的区别

两种不同的动态模块创建方式

  • 静态模块
  • 传统动态模块方式实现
  • 三种不同的方法命名
  • 使用ConfigurableModuleBuilder
    • 异步动态模块
    • 如果想要把动态模块全局化
    • 延缓执行动态模块

静态模块

静态模块非常好理解,就是使用imports关键字导入其他的模块,并在@Moduleimports属性中加上,代码如下:

import { Module } from '@nestjs/common';
import { AuthService } from './auth.service';
import { UsersModule } from '../users/users.module';@Module({imports: [UsersModule],providers: [AuthService],exports: [AuthService],
})
export class AuthModule {}

导入之后便可以使用UsersModule内的Server,或者说注入,代码如下:

import { Injectable } from '@nestjs/common';
import { UsersService } from '../users/users.service';@Injectable()
export class AuthService {constructor(private usersService: UsersService) {}/*Implementation that makes use of this.usersService*/
}

注:在Nest中,如果只是在AuthService 文件内使用import通过路径导入UsersService ,没有在模块内导入UsersModule模块,那么在构造函数中加入UsersService也是报错的,因为Nest的机制是以模块为单位

换句话说,想在某个服务下引用其他模块的服务,必须先导入该服务所在的模块

传统动态模块方式实现

动态模块的使用场景,或者说为什么要有动态模块的出现,原因在于开发场景的不同,例如一个系统可能会在不同周期使用不同的数据库?就好比开发也有生产环境、开发环境、测试环境,不同环境下需要导入的.env或许有些不同

所以动态模块就是可以根据不同的条件去导入不同的Module,进而,使用不同的Service

在文档中,讲述的方式是一种倒叙的形式,Let's see how this works. It's helpful if we start from the end-goal of how this might look from the consuming module's perspective, and then work backwards.

  1. 假设需要导入一个用于配置的模块
    静态模式下的代码如下:
@Module({imports: [ConfigModule],controllers: [AppController],providers: [AppService],
})
export class AppModule {}
  1. 因为是动态的,所以这个ConfigModule就应该有一个接口方便开发人员去替换不同的配置,例如可以传入一个配置文件的路径,然后通过fs便可以读取里面的内容,代码如下:
@Module({imports: [ConfigModule.register({ folder: './config' })],controllers: [AppController],providers: [AppService],
})
export class AppModule {}
  1. 想象一下,一个模块包含哪些内容?有importscontrollersprovidersexports,所以调用ConfigModule.register({ folder: './config' })返回的就是一个包含上述内容的东西。而ConfigModule内部包含有一个静态方法register,代码如下:
import { DynamicModule, Module } from '@nestjs/common';
import { ConfigService } from './config.service';@Module({})
export class ConfigModule {static register(): DynamicModule {return {module: ConfigModule,providers: [ConfigService],exports: [ConfigService],};}
}
  1. 传递的{ folder: './config' }如何进行消费?代码如下:
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],};}
}

注:在TypeScript中,Record<K, T>是一个内置的工具类型,它用于构建一个对象类型,该对象的所有属性键都属于类型K,而对应的属性值则属于类型T

注:在Nest文档中推荐将'CONFIG_OPTIONS'定义为单独文件中的常量,也就是唯一值

静态方法register接收一个配置选项,然后作为提供者'CONFIG_OPTIONS'的值,被注入到了ConfigService中,代码如下:

import * as dotenv from 'dotenv';
import * as fs from 'fs'; // 前面提到的fs
import * as path from 'path';
import { Injectable, Inject } from '@nestjs/common';
import { EnvConfig } from './interfaces';@Injectable()
export class ConfigService {private readonly envConfig: EnvConfig;// 注入'CONFIG_OPTIONS',拿到{ folder: './config' }constructor(@Inject('CONFIG_OPTIONS') private options: Record<string, any>) {// 根据运行环境找到.env文件const filePath = `${process.env.NODE_ENV || 'development'}.env`;// 构建绝对路径const envFile = path.resolve(__dirname, '../../', options.folder, filePath);// 读取内容,并解析this.envConfig = dotenv.parse(fs.readFileSync(envFile));}// 读取解析内容的方法get(key: string): string {return this.envConfig[key];}
}

这里有一个细节就是为什么要用 dotenv.parse(),很简单,想想.env文件是怎么存储内容的,KEY=value

那么至此,就完成了可以通过传入不同的options.folder,去形成不同的ConfigService,其他的模块使用的便是动态ConfigService

三种不同的方法命名

在上面的静态方法中,方法的命名为register,这是一个社区规范,或者说默认情况下就是这个名字,此外还有两种,分别是forRootforFeature

forRoot很好理解,Root是根的意思,该方法是用于全局或者基础配置,是用在AppModule中的,一般只会调用一次

forFeature则用于特定功能或者子模块的配置

总的来说,就是通过命名向其他的开发者传达当前这个动态模块是用于什么场景的

使用ConfigurableModuleBuilder

Nest的官方推荐新手使用ConfigurableModuleBuilder去搭建动态模块

  1. 定义接收参数的类型,例如{ folder: './config' },就需要定义folder:string,代码如下:
export interface ConfigModuleOptions {folder: string;
}
  1. 调用ConfigurableModuleBuilder,构造动态模块,代码如下:
// config.module-definition
import { ConfigurableModuleBuilder } from '@nestjs/common';
import { ConfigModuleOptions } from './interfaces/config-module-options.interface';export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN } =new ConfigurableModuleBuilder<ConfigModuleOptions>().build();
  1. config.module.ts里利用生成的动态模块,代码如下:
import { Module } from '@nestjs/common';
import { ConfigService } from './config.service';
import { ConfigurableModuleClass } from './config.module-definition';@Module({providers: [ConfigService],exports: [ConfigService],
})
export class ConfigModule extends ConfigurableModuleClass {}

这里非常抽象,但我们先看其他的步骤

  1. 在根模块内,或者说导入动态模块的模块内,代码如下:
@Module({imports: [ConfigModule.register({ folder: './config' }),// or alternatively:// ConfigModule.registerAsync({//   useFactory: () => {//     return {//       folder: './config',//     }//   },//   inject: [...any extra dependencies...]// }),],
})
export class AppModule {} // 这里是根模块
  1. configService内,需要将'CONFIG_OPTIONS'替换为在文件config.module-definition导出的'MODULE_OPTIONS_TOKEN',代码如下:
@Injectable()
export class ConfigService {constructor(@Inject(MODULE_OPTIONS_TOKEN) private options: ConfigModuleOptions) { ... }
}

对比在哪?第一个是在config.module.ts,从

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],};}
}

变成了👇

import { Module } from '@nestjs/common';
import { ConfigService } from './config.service';
import { ConfigurableModuleClass } from './config.module-definition';@Module({providers: [ConfigService],exports: [ConfigService],
})
export class ConfigModule extends ConfigurableModuleClass {}

减去了return里面的代码和静态方法return笔者不觉得这样更适合新手,非常抽象

第二个变化就是'CONFIG_OPTIONS'变成了'MODULE_OPTIONS_TOKEN'

所以ConfigurableModuleBuilder的作用就是,直接帮开发者省去了构造register方法和return的流程,但抽象的是在ConfigModule里的register哪来的?所以这就是抽象,在阅读官方文档时真的绕

从这里也可以看出,使用ConfigurableModuleBuilder后,在AppModule 使用的方法是register,所以说明这是默认的命名,如果要改名怎么办?比方说使用forRoot,需要调用.setClassMethodName(),代码如下:

export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN } =new ConfigurableModuleBuilder<ConfigModuleOptions>().setClassMethodName('forRoot').build();

异步动态模块

在上面的例子中,是主动的传入一个配置项,例如路径,但如果配置需要异步获取呢?需要等待Promise解析后才能得到呢?

Nest提供了registerAsync(或者forRootAsync)方法,代码如下:

@Module({imports: [ConfigModule.registerAsync({useClass: ConfigModuleOptionsFactory,}),],
})
export class AppModule {}

这里抽象的是,ConfigModuleOptionsFactory必须要有一个create方法,如果没有,那么会在解析的过程中出现问题,并且文档并没有给出ConfigModuleOptionsFactory究竟是怎么样的,但可以模拟一下,代码如下:

import { Injectable } from '@nestjs/common';
import { ConfigModuleOptions } from './config.module-definition';@Injectable()
export class ConfigModuleOptionsFactory {async create(): Promise<ConfigModuleOptions> {// 这里可以进行异步操作,例如从数据库或文件系统加载配置return {folder: 'path/to/config/folder',};}
}

这个create方法可以自定义取名,例如改成createConfigOptions,代码如下:

export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN } =new ConfigurableModuleBuilder<ConfigModuleOptions>().setFactoryMethodName('createConfigOptions').build();

一切的目的,都是让开发者通过命名清楚这个动态模块是干什么的,见名知意

如果想要把动态模块全局化

代码如下:

export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN } = new ConfigurableModuleBuilder<ConfigModuleOptions>().setExtras({isGlobal: true,},(definition, extras) => ({...definition,global: extras.isGlobal,}),).build();

.setExtras()的第一个形参名字是extras,所以第二个函数参数里的extras.isGlobal就是true,这样设置之后,就可以在AppModule内加多一个isGlobal属性,代码如下:

@Module({imports: [ConfigModule.register({isGlobal: true,folder: './config',}),],
})
export class AppModule {}

延缓执行动态模块

Dynamic modules的最后一个章节中,提供了延缓执行动态模块的方法,代码如下:

import { Module } from '@nestjs/common';
import { ConfigService } from './config.service';
import { ConfigurableModuleClass, ASYNC_OPTIONS_TYPE, OPTIONS_TYPE } from './config.module-definition';@Module({providers: [ConfigService],exports: [ConfigService],
})
export class ConfigModule extends ConfigurableModuleClass {static register(options: typeof OPTIONS_TYPE): DynamicModule {return {// your custom logic here...super.register(options),};}static registerAsync(options: typeof ASYNC_OPTIONS_TYPE): DynamicModule {return {// your custom logic here...super.registerAsync(options),};}
}

options传进来之后,在返回模块之前,可以执行想要的逻辑,例如日志记录,调用了哪个动态模块,就可以在这里加上了


文章转载自:
http://bosnia.mcjp.cn
http://notch.mcjp.cn
http://transracial.mcjp.cn
http://thermogram.mcjp.cn
http://deficit.mcjp.cn
http://disfeature.mcjp.cn
http://agamemnon.mcjp.cn
http://trot.mcjp.cn
http://arteritis.mcjp.cn
http://bakemeat.mcjp.cn
http://jdk.mcjp.cn
http://negligence.mcjp.cn
http://kittle.mcjp.cn
http://tardily.mcjp.cn
http://barretry.mcjp.cn
http://tennis.mcjp.cn
http://arillus.mcjp.cn
http://profuseness.mcjp.cn
http://bairiki.mcjp.cn
http://tzitzis.mcjp.cn
http://enarchist.mcjp.cn
http://unstained.mcjp.cn
http://cymiferous.mcjp.cn
http://bead.mcjp.cn
http://hydrotrope.mcjp.cn
http://bulgaria.mcjp.cn
http://avt.mcjp.cn
http://sealwort.mcjp.cn
http://precarcinogen.mcjp.cn
http://pediarchy.mcjp.cn
http://drama.mcjp.cn
http://reignite.mcjp.cn
http://absquatulate.mcjp.cn
http://hunger.mcjp.cn
http://staminodium.mcjp.cn
http://ambulate.mcjp.cn
http://guillotine.mcjp.cn
http://bovarism.mcjp.cn
http://tales.mcjp.cn
http://widf.mcjp.cn
http://thyrotropic.mcjp.cn
http://fleeceable.mcjp.cn
http://prejudge.mcjp.cn
http://zeuxis.mcjp.cn
http://chipping.mcjp.cn
http://orthophotograph.mcjp.cn
http://mynheer.mcjp.cn
http://wamus.mcjp.cn
http://seletron.mcjp.cn
http://platycephaly.mcjp.cn
http://uropygia.mcjp.cn
http://hypergraph.mcjp.cn
http://nonrecombinant.mcjp.cn
http://premiere.mcjp.cn
http://potbelly.mcjp.cn
http://horseshoer.mcjp.cn
http://iceboat.mcjp.cn
http://anatase.mcjp.cn
http://shandrydan.mcjp.cn
http://radioresistance.mcjp.cn
http://consumption.mcjp.cn
http://ulsterite.mcjp.cn
http://wheelbase.mcjp.cn
http://didactical.mcjp.cn
http://synoecize.mcjp.cn
http://chiroplasty.mcjp.cn
http://deus.mcjp.cn
http://clodpate.mcjp.cn
http://connectionless.mcjp.cn
http://stockjobbing.mcjp.cn
http://briery.mcjp.cn
http://monoecious.mcjp.cn
http://yugoslavic.mcjp.cn
http://desmidian.mcjp.cn
http://ventripotent.mcjp.cn
http://furuncle.mcjp.cn
http://signior.mcjp.cn
http://sticktight.mcjp.cn
http://bassein.mcjp.cn
http://stipulator.mcjp.cn
http://aragon.mcjp.cn
http://gel.mcjp.cn
http://potted.mcjp.cn
http://mathematics.mcjp.cn
http://gheber.mcjp.cn
http://itabira.mcjp.cn
http://inerasable.mcjp.cn
http://beautyberry.mcjp.cn
http://neuroleptanalgesia.mcjp.cn
http://immersion.mcjp.cn
http://cantaloup.mcjp.cn
http://idiomorphic.mcjp.cn
http://notalgia.mcjp.cn
http://manchurian.mcjp.cn
http://borrowed.mcjp.cn
http://signatary.mcjp.cn
http://pickproof.mcjp.cn
http://frump.mcjp.cn
http://hideously.mcjp.cn
http://orometry.mcjp.cn
http://www.15wanjia.com/news/81308.html

相关文章:

  • 建设银行招聘网站甘肃分行杭州上城区抖音seo如何
  • 网站页面组成部分网络营销岗位
  • 档案馆建设网站网络推广公司
  • t.cn这种网站怎么做的关键词简谱
  • 评析网站建设报价单百度网址大全怎么设为主页
  • 国内用python做的网站搜索引擎分类
  • vs网站开发 百度文库安徽seo推广
  • 全网网站建设维护河南省干部任免最新公示
  • 诚信网站费用网页设计与制作软件
  • 网站列表页是啥最有效的app推广方式有哪些
  • 建设360导航网站的目的是什么意思北京seo课程
  • org域名做网站郑州网站顾问热狗网
  • 做图表用的网站河南疫情最新消息
  • 嘉兴城乡建设局门户网站移动端关键词排名优化
  • 一个静态网站怎么做网站推广的目的是什么
  • 桂林网站建设谷歌seo招聘
  • 深圳福田网站建设镇江网站建设
  • 政府网站建设赏析推动防控措施持续优化
  • 莱芜网站建设哪家好李飞seo
  • 手机网站免费做app百度网站是什么
  • 温州网站建设seo网络营销推广方案范文
  • 北京网站优化合作搜索引擎论文3000字
  • 自学网站建设靠谱吗俄罗斯网络攻击数量增长了80%
  • 怎么上传文件到ftp网站郑州百度seo关键词
  • 西安做网站公司seo内容优化
  • 合川网站制作中国十大企业管理培训机构
  • 网站如何做导航条下拉菜单百度链接
  • 在线图表seo优化服务价格
  • 怎么做免费网站推广网络引流怎么做啊?
  • 网站建设编辑工作总结2022今日最新军事新闻