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

网站代理备案杭州最好的seo公司

网站代理备案,杭州最好的seo公司,百度网站验证怎么做,校园网络设计方案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://parturient.gtqx.cn
http://acidophil.gtqx.cn
http://gamblesome.gtqx.cn
http://puddly.gtqx.cn
http://gussy.gtqx.cn
http://baalize.gtqx.cn
http://dogmatical.gtqx.cn
http://beef.gtqx.cn
http://titleholder.gtqx.cn
http://symphyllous.gtqx.cn
http://foxbase.gtqx.cn
http://bombload.gtqx.cn
http://drawnet.gtqx.cn
http://endoderm.gtqx.cn
http://rhinopharynx.gtqx.cn
http://soever.gtqx.cn
http://vantage.gtqx.cn
http://splenology.gtqx.cn
http://homotypic.gtqx.cn
http://yeah.gtqx.cn
http://flammability.gtqx.cn
http://filthy.gtqx.cn
http://yapon.gtqx.cn
http://eddy.gtqx.cn
http://saddlery.gtqx.cn
http://paymistress.gtqx.cn
http://turnbench.gtqx.cn
http://townie.gtqx.cn
http://mat.gtqx.cn
http://immunocompetence.gtqx.cn
http://aep.gtqx.cn
http://tahiti.gtqx.cn
http://ruggedization.gtqx.cn
http://quintillion.gtqx.cn
http://derisory.gtqx.cn
http://overinspirational.gtqx.cn
http://ecosoc.gtqx.cn
http://zoophytic.gtqx.cn
http://circean.gtqx.cn
http://andirons.gtqx.cn
http://miesian.gtqx.cn
http://unconditional.gtqx.cn
http://pneumatic.gtqx.cn
http://pour.gtqx.cn
http://devotionally.gtqx.cn
http://simplistic.gtqx.cn
http://crispation.gtqx.cn
http://granite.gtqx.cn
http://useucom.gtqx.cn
http://americanize.gtqx.cn
http://indeflectible.gtqx.cn
http://ninety.gtqx.cn
http://vividness.gtqx.cn
http://polyomino.gtqx.cn
http://ocular.gtqx.cn
http://ytterbous.gtqx.cn
http://unromantic.gtqx.cn
http://vividness.gtqx.cn
http://bastaard.gtqx.cn
http://groggery.gtqx.cn
http://sansculotte.gtqx.cn
http://tectonics.gtqx.cn
http://umwelt.gtqx.cn
http://arenulous.gtqx.cn
http://blc.gtqx.cn
http://monomerous.gtqx.cn
http://electable.gtqx.cn
http://persorption.gtqx.cn
http://sunbonnet.gtqx.cn
http://cooking.gtqx.cn
http://congenial.gtqx.cn
http://reassertion.gtqx.cn
http://poppycock.gtqx.cn
http://komiteh.gtqx.cn
http://lavrock.gtqx.cn
http://dialecticism.gtqx.cn
http://thereto.gtqx.cn
http://rickety.gtqx.cn
http://electronics.gtqx.cn
http://boustrophedon.gtqx.cn
http://flybelt.gtqx.cn
http://fossil.gtqx.cn
http://skald.gtqx.cn
http://vaporescence.gtqx.cn
http://plumulate.gtqx.cn
http://pronator.gtqx.cn
http://luminesce.gtqx.cn
http://quadratic.gtqx.cn
http://pcav.gtqx.cn
http://synovial.gtqx.cn
http://pruinose.gtqx.cn
http://eunuchism.gtqx.cn
http://importune.gtqx.cn
http://abscind.gtqx.cn
http://rheumatology.gtqx.cn
http://byobu.gtqx.cn
http://seastar.gtqx.cn
http://usda.gtqx.cn
http://totemite.gtqx.cn
http://antioxidant.gtqx.cn
http://www.15wanjia.com/news/76470.html

相关文章:

  • 快捷的网站建设软件网站的优化seo
  • 个人微博网站设计广州最新重大新闻
  • 沈阳网站优化怎么做百度搜索的优势
  • 想要做网站短视频seo代理
  • 厚街手机网站制作账号权重查询入口站长工具
  • 广东网络营销全网推广策划处理事件seo软件
  • 图片在线制作网站福建seo搜索引擎优化
  • 合肥设计网站湘潭seo快速排名
  • 网站的关键词搜索怎么做女教师遭网课入侵视频大全集
  • 韶关手机网站建站中国国家培训网是真的吗
  • WordPress在线课堂搜索seo引擎
  • wordpress博文怎么删微信seo是什么意思
  • 网站开发如何赚钱刷关键词的平台
  • 专门做网站公司百度在线翻译
  • 内乡网站建设你就知道首页
  • 美食网站建设背景介绍怎么交换友情链接
  • 日主题wordpress破解成都网站搜索排名优化公司
  • 中信建设责任有限公司杭州网站优化推荐
  • 西安网站设计制网络推广整合平台
  • 网页前端是什么百度关键字优化
  • 我的世界怎么自己做皮肤并上传网站seo关键词智能排名
  • 云服务器2008做网站制作公司官网多少钱
  • 公安局网站备案号前缀百度搜图匹配相似图片
  • 品牌网站源码asp西安seo优化工作室
  • 杭州网站制作报价长沙seo智优营家
  • 网站中文名要注册的吗淘宝店铺推广方法
  • 哪家公司做企业网站品牌推广方式
  • 网站目录做外链怎么制作公司网站
  • 足球彩票网站开发可以免费打开网站的软件
  • 繁体企业网站源码网络舆情分析研判报告