加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
556.4f768300e856fdd8.js 199.96 KB
一键复制 编辑 原始数据 按行查看 历史
zhangjing 提交于 2023-11-13 16:41 . push
"use strict";(self.webpackChunkdocs_nestjs_com=self.webpackChunkdocs_nestjs_com||[]).push([[556],{8556:(N,q,c)=>{c.r(q),c.d(q,{FundamentalsModule:()=>R});var y=c(6814),p=c(8833),b=c(6208),d=c(2437),e=c(4946),l=c(6663);let w=(()=>{class t extends d.y{static \u0275fac=function(){let o;return function(s){return(o||(o=e.n5z(t)))(s||t)}}();static \u0275cmp=e.Xpm({type:t,selectors:[["app-async-components"]],features:[e.qOj],decls:51,vars:0,consts:[[1,"content"],["contentReference",""],[1,"github-links"],["href","https://github.com/ChuTingzj/docs.nestjs.zh-cn.com/tree/master/content/fundamentals/async-components.md","aria-label","Suggest Edits","title","Suggest Edits"],[1,"fas","fa-edit"],["id","asynchronous-providers"],[1,"language-typescript"],[1,"info"],["routerLink","/fundamentals/custom-providers"],["appAnchor","","id","injection"],["appAnchor","","id","example"],["routerLink","/recipes/sql-typeorm"]],template:function(n,s){1&n&&(e.TgZ(0,"div",0,1)(2,"div",2)(3,"a",3),e._UZ(4,"i",4),e.qZA()(),e.TgZ(5,"h3",5),e._uU(6,"Asynchronous providers"),e.qZA(),e.TgZ(7,"p"),e._uU(8,"At times, the application start should be delayed until one or more "),e.TgZ(9,"strong"),e._uU(10,"asynchronous tasks"),e.qZA(),e._uU(11," are completed. For example, you may not want to start accepting requests until the connection with the database has been established. You can achieve this using asynchronous providers."),e.qZA(),e.TgZ(12,"p"),e._uU(13,"The syntax for this is to use "),e.TgZ(14,"code"),e._uU(15,"async/await"),e.qZA(),e._uU(16," with the "),e.TgZ(17,"code"),e._uU(18,"useFactory"),e.qZA(),e._uU(19," syntax. The factory returns a "),e.TgZ(20,"code"),e._uU(21,"Promise"),e.qZA(),e._uU(22,", and the factory function can "),e.TgZ(23,"code"),e._uU(24,"await"),e.qZA(),e._uU(25," asynchronous tasks. Nest will await resolution of the promise before instantiating any class that depends on (injects) such a provider."),e.qZA(),e.TgZ(26,"pre")(27,"code",6),e._uU(28,"\n{\n provide: 'ASYNC_CONNECTION',\n useFactory: async () => {\n const connection = await createConnection(options);\n return connection;\n },\n}\n"),e.qZA()(),e.TgZ(29,"blockquote",7)(30,"strong"),e._uU(31,"Hint"),e.qZA(),e._uU(32," Learn more about custom provider syntax "),e.TgZ(33,"a",8),e._uU(34,"here"),e.qZA(),e._uU(35,".\n"),e.qZA(),e.TgZ(36,"h4",9)(37,"span"),e._uU(38,"Injection"),e.qZA()(),e.TgZ(39,"p"),e._uU(40,"Asynchronous providers are injected to other components by their tokens, like any other provider. In the example above, you would use the construct "),e.TgZ(41,"code"),e._uU(42,"@Inject('ASYNC_CONNECTION')"),e.qZA(),e._uU(43,"."),e.qZA(),e.TgZ(44,"h4",10)(45,"span"),e._uU(46,"Example"),e.qZA()(),e.TgZ(47,"p")(48,"a",11),e._uU(49,"The TypeORM recipe"),e.qZA(),e._uU(50," has a more substantial example of an asynchronous provider."),e.qZA()())},dependencies:[l.U,p.rH],encapsulation:2,changeDetection:0})}return t})();var h=c(328),U=c(8327);let x=(()=>{class t extends d.y{static \u0275fac=function(){let o;return function(s){return(o||(o=e.n5z(t)))(s||t)}}();static \u0275cmp=e.Xpm({type:t,selectors:[["app-circular-dependency"]],features:[e.qOj],decls:150,vars:24,consts:[[1,"content"],["contentReference",""],[1,"github-links"],["href","https://github.com/ChuTingzj/docs.nestjs.zh-cn.com/tree/master/content/fundamentals/circular-dependency.md","aria-label","Suggest Edits","title","Suggest Edits"],[1,"fas","fa-edit"],["id","circular-dependency"],[1,"warning"],["rel","nofollow","target","_blank","href","https://github.com/nestjs/nest/issues/1181#issuecomment-430197191"],["appAnchor","","id","forward-reference"],[1,"filename"],["appa7689985e4e94f9790399d2d828ab34d0c1adf09",""],[1,"language-typescript"],[1,"info"],["app48f4bec0a8728c3983c7b130b8d7d72d42d04ab4",""],["rel","nofollow","target","_blank","href","https://github.com/nestjs/nest/issues/5778"],["appAnchor","","id","moduleref-class-alternative"],["routerLink","/fundamentals/module-ref"],["appAnchor","","id","module-forward-reference"],["appab402790976ee0745a2bd13f43ce55f883d93f94",""],["appe73a70a9fd065f3f37aeb36bb4d987461f56cae5",""]],template:function(n,s){if(1&n&&(e.TgZ(0,"div",0,1)(2,"div",2)(3,"a",3),e._UZ(4,"i",4),e.qZA()(),e.TgZ(5,"h3",5),e._uU(6,"Circular dependency"),e.qZA(),e.TgZ(7,"p"),e._uU(8,"A circular dependency occurs when two classes depend on each other. For example, class A needs class B, and class B also needs class A. Circular dependencies can arise in Nest between modules and between providers."),e.qZA(),e.TgZ(9,"p"),e._uU(10,"While circular dependencies should be avoided where possible, you can't always do so. In such cases, Nest enables resolving circular dependencies between providers in two ways. In this chapter, we describe using "),e.TgZ(11,"strong"),e._uU(12,"forward referencing"),e.qZA(),e._uU(13," as one technique, and using the "),e.TgZ(14,"strong"),e._uU(15,"ModuleRef"),e.qZA(),e._uU(16," class to retrieve a provider instance from the DI container as another."),e.qZA(),e.TgZ(17,"p"),e._uU(18,"We also describe resolving circular dependencies between modules."),e.qZA(),e.TgZ(19,"blockquote",6)(20,"strong"),e._uU(21,"Warning"),e.qZA(),e._uU(22,' A circular dependency might also be caused when using "barrel files"/index.ts files to group imports. Barrel files should be omitted when it comes to module/provider classes. For example, barrel files should not be used when importing files within the same directory as the barrel file, i.e. '),e.TgZ(23,"code"),e._uU(24,"cats/cats.controller"),e.qZA(),e._uU(25," should not import "),e.TgZ(26,"code"),e._uU(27,"cats"),e.qZA(),e._uU(28," to import the "),e.TgZ(29,"code"),e._uU(30,"cats/cats.service"),e.qZA(),e._uU(31," file. For more details please also see "),e.TgZ(32,"a",7),e._uU(33,"this github issue"),e.qZA(),e._uU(34,".\n"),e.qZA(),e.TgZ(35,"h4",8)(36,"span"),e._uU(37,"Forward reference"),e.qZA()(),e.TgZ(38,"p"),e._uU(39,"A "),e.TgZ(40,"strong"),e._uU(41,"forward reference"),e.qZA(),e._uU(42," allows Nest to reference classes which aren't yet defined using the "),e.TgZ(43,"code"),e._uU(44,"forwardRef()"),e.qZA(),e._uU(45," utility function. For example, if "),e.TgZ(46,"code"),e._uU(47,"CatsService"),e.qZA(),e._uU(48," and "),e.TgZ(49,"code"),e._uU(50,"CommonService"),e.qZA(),e._uU(51," depend on each other, both sides of the relationship can use "),e.TgZ(52,"code"),e._uU(53,"@Inject()"),e.qZA(),e._uU(54," and the "),e.TgZ(55,"code"),e._uU(56,"forwardRef()"),e.qZA(),e._uU(57," utility to resolve the circular dependency. Otherwise Nest won't instantiate them because all of the essential metadata won't be available. Here's an example:"),e.qZA(),e.TgZ(58,"span",9),e._uU(59),e.ALo(60,"extension"),e._UZ(61,"app-tabs",null,10),e.qZA(),e.TgZ(63,"pre")(64,"code",11),e._uU(65,"\n@Injectable()\nexport class CatsService {\n constructor(\n @Inject(forwardRef(() => CommonService))\n private commonService: CommonService,\n ) {}\n}\n"),e.qZA()(),e.TgZ(66,"pre")(67,"code",11),e._uU(68,"\n@Injectable()\n@Dependencies(forwardRef(() => CommonService))\nexport class CatsService {\n constructor(commonService) {\n this.commonService = commonService;\n }\n}\n"),e.qZA()(),e.TgZ(69,"blockquote",12)(70,"strong"),e._uU(71,"Hint"),e.qZA(),e._uU(72," The "),e.TgZ(73,"code"),e._uU(74,"forwardRef()"),e.qZA(),e._uU(75," function is imported from the "),e.TgZ(76,"code"),e._uU(77,"@nestjs/common"),e.qZA(),e._uU(78," package.\n"),e.qZA(),e.TgZ(79,"p"),e._uU(80,"That covers one side of the relationship. Now let's do the same with "),e.TgZ(81,"code"),e._uU(82,"CommonService"),e.qZA(),e._uU(83,":"),e.qZA(),e.TgZ(84,"span",9),e._uU(85),e.ALo(86,"extension"),e._UZ(87,"app-tabs",null,13),e.qZA(),e.TgZ(89,"pre")(90,"code",11),e._uU(91,"\n@Injectable()\nexport class CommonService {\n constructor(\n @Inject(forwardRef(() => CatsService))\n private catsService: CatsService,\n ) {}\n}\n"),e.qZA()(),e.TgZ(92,"pre")(93,"code",11),e._uU(94,"\n@Injectable()\n@Dependencies(forwardRef(() => CatsService))\nexport class CommonService {\n constructor(catsService) {\n this.catsService = catsService;\n }\n}\n"),e.qZA()(),e.TgZ(95,"blockquote",6)(96,"strong"),e._uU(97,"Warning"),e.qZA(),e._uU(98," The order of instantiation is indeterminate. Make sure your code does not depend on which constructor is called first. Having circular dependencies depend on providers with "),e.TgZ(99,"code"),e._uU(100,"Scope.REQUEST"),e.qZA(),e._uU(101," can lead to undefined dependencies. More information available "),e.TgZ(102,"a",14),e._uU(103,"here"),e.qZA()(),e.TgZ(104,"h4",15)(105,"span"),e._uU(106,"ModuleRef class alternative"),e.qZA()(),e.TgZ(107,"p"),e._uU(108,"An alternative to using "),e.TgZ(109,"code"),e._uU(110,"forwardRef()"),e.qZA(),e._uU(111," is to refactor your code and use the "),e.TgZ(112,"code"),e._uU(113,"ModuleRef"),e.qZA(),e._uU(114," class to retrieve a provider on one side of the (otherwise) circular relationship. Learn more about the "),e.TgZ(115,"code"),e._uU(116,"ModuleRef"),e.qZA(),e._uU(117," utility class "),e.TgZ(118,"a",16),e._uU(119,"here"),e.qZA(),e._uU(120,"."),e.qZA(),e.TgZ(121,"h4",17)(122,"span"),e._uU(123,"Module forward reference"),e.qZA()(),e.TgZ(124,"p"),e._uU(125,"In order to resolve circular dependencies between modules, use the same "),e.TgZ(126,"code"),e._uU(127,"forwardRef()"),e.qZA(),e._uU(128," utility function on both sides of the modules association. For example:"),e.qZA(),e.TgZ(129,"span",9),e._uU(130),e.ALo(131,"extension"),e._UZ(132,"app-tabs",null,18),e.qZA(),e.TgZ(134,"pre")(135,"code",11),e._uU(136,"\n@Module({\n imports: [forwardRef(() => CatsModule)],\n})\nexport class CommonModule {}\n"),e.qZA()(),e.TgZ(137,"p"),e._uU(138,"That covers one side of the relationship. Now let's do the same with "),e.TgZ(139,"code"),e._uU(140,"CatsModule"),e.qZA(),e._uU(141,":"),e.qZA(),e.TgZ(142,"span",9),e._uU(143),e.ALo(144,"extension"),e._UZ(145,"app-tabs",null,19),e.qZA(),e.TgZ(147,"pre")(148,"code",11),e._uU(149,"\n@Module({\n imports: [forwardRef(() => CommonModule)],\n})\nexport class CatsModule {}\n"),e.qZA()()()),2&n){const a=e.MAs(62),r=e.MAs(88),i=e.MAs(133),u=e.MAs(146);e.xp6(59),e.hij(" ",e.xi3(60,12,"cats.service",a.isJsActive),"\n"),e.xp6(4),e.ekj("hide",a.isJsActive),e.xp6(3),e.ekj("hide",!a.isJsActive),e.xp6(19),e.hij(" ",e.xi3(86,15,"common.service",r.isJsActive),"\n"),e.xp6(4),e.ekj("hide",r.isJsActive),e.xp6(3),e.ekj("hide",!r.isJsActive),e.xp6(38),e.hij(" ",e.xi3(131,18,"common.module",i.isJsActive),"\n"),e.xp6(13),e.hij(" ",e.xi3(144,21,"cats.module",u.isJsActive),"\n")}},dependencies:[h.n,l.U,p.rH,U.F],encapsulation:2,changeDetection:0})}return t})();var m=c(3694);let C=(()=>{class t extends d.y{static \u0275fac=function(){let o;return function(s){return(o||(o=e.n5z(t)))(s||t)}}();static \u0275cmp=e.Xpm({type:t,selectors:[["app-dependency-injection"]],features:[e.qOj],decls:465,vars:36,consts:[[1,"content"],["contentReference",""],[1,"github-links"],["href","https://github.com/ChuTingzj/docs.nestjs.zh-cn.com/tree/master/content/fundamentals/dependency-injection.md","aria-label","Suggest Edits","title","Suggest Edits"],[1,"fas","fa-edit"],["id","custom-providers"],["rel","nofollow","target","_blank","href","https://docs.nestjs.com/providers#dependency-injection"],["appAnchor","","id","di-fundamentals"],["rel","nofollow","target","_blank","href","https://en.wikipedia.org/wiki/Inversion_of_control"],["rel","nofollow","target","_blank","href","https://docs.nestjs.com/providers"],[1,"filename"],["app0ac9cf8222fd80d6169b0d691f5a58c681e05903",""],[1,"language-typescript"],["appe97cb22e1938ea1a907e5c4019a533e0825c16d5",""],["app4f135e4d824000658b5a05fc15c713db47265db5",""],["start","3"],["href","/fundamentals/custom-providers#standard-providers"],["appAnchor","","id","standard-providers"],["appAnchor","","id","custom-providers-1"],[1,"info"],["appAnchor","","id","value-providers-usevalue"],["rel","nofollow","target","_blank","href","https://www.typescriptlang.org/docs/handbook/type-compatibility.html"],["appAnchor","","id","non-class-based-provider-tokens"],["href","/fundamentals/custom-providers#di-fundamentals"],[1,"warning"],["rel","nofollow","target","_blank","href","https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol"],["rel","nofollow","target","_blank","href","https://www.typescriptlang.org/docs/handbook/enums.html"],["appf5b5362574ed0db76e197b26a3b8f8e5253cb490",""],["appAnchor","","id","class-providers-useclass"],["appAnchor","","id","factory-providers-usefactory"],["app39e970addc891a38991512d4f099b764c73d34a5",""],["appAnchor","","id","alias-providers-useexisting"],["appAnchor","","id","non-service-based-providers"],["appAnchor","","id","export-custom-provider"],["app6c06a00a3467a0ffc1c488424ad28db3ea44046d",""],["app4be7cff6fa643a661848dd59d6215dbb0699ea4a",""]],template:function(n,s){if(1&n&&(e.TgZ(0,"div",0,1)(2,"div",2)(3,"a",3),e._UZ(4,"i",4),e.qZA()(),e.TgZ(5,"h3",5),e._uU(6,"Custom providers"),e.qZA(),e.TgZ(7,"p"),e._uU(8,"In earlier chapters, we touched on various aspects of "),e.TgZ(9,"strong"),e._uU(10,"Dependency Injection (DI)"),e.qZA(),e._uU(11," and how it is used in Nest. One example of this is the "),e.TgZ(12,"a",6),e._uU(13,"constructor based"),e.qZA(),e._uU(14," dependency injection used to inject instances (often service providers) into classes. You won't be surprised to learn that Dependency Injection is built into the Nest core in a fundamental way. So far, we've only explored one main pattern. As your application grows more complex, you may need to take advantage of the full features of the DI system, so let's explore them in more detail."),e.qZA(),e.TgZ(15,"h4",7)(16,"span"),e._uU(17,"DI fundamentals"),e.qZA()(),e.TgZ(18,"p"),e._uU(19,"Dependency injection is an "),e.TgZ(20,"a",8),e._uU(21,"inversion of control (IoC)"),e.qZA(),e._uU(22," technique wherein you delegate instantiation of dependencies to the IoC container (in our case, the NestJS runtime system), instead of doing it in your own code imperatively. Let's examine what's happening in this example from the "),e.TgZ(23,"a",9),e._uU(24,"Providers chapter"),e.qZA(),e._uU(25,"."),e.qZA(),e.TgZ(26,"p"),e._uU(27,"First, we define a provider. The "),e.TgZ(28,"code"),e._uU(29,"@Injectable()"),e.qZA(),e._uU(30," decorator marks the "),e.TgZ(31,"code"),e._uU(32,"CatsService"),e.qZA(),e._uU(33," class as a provider."),e.qZA(),e.TgZ(34,"span",10),e._uU(35),e.ALo(36,"extension"),e._UZ(37,"app-tabs",null,11),e.qZA(),e.TgZ(39,"pre")(40,"code",12),e._uU(41,"\nimport { Injectable } from '@nestjs/common';\nimport { Cat } from './interfaces/cat.interface';\n\n@Injectable()\nexport class CatsService {\n private readonly cats: Cat[] = [];\n\n findAll(): Cat[] {\n return this.cats;\n }\n}\n"),e.qZA()(),e.TgZ(42,"pre")(43,"code",12),e._uU(44,"\nimport { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class CatsService {\n constructor() {\n this.cats = [];\n }\n\n findAll() {\n return this.cats;\n }\n}\n"),e.qZA()(),e.TgZ(45,"p"),e._uU(46,"Then we request that Nest inject the provider into our controller class:"),e.qZA(),e.TgZ(47,"span",10),e._uU(48),e.ALo(49,"extension"),e._UZ(50,"app-tabs",null,13),e.qZA(),e.TgZ(52,"pre")(53,"code",12),e._uU(54,"\nimport { Controller, Get } from '@nestjs/common';\nimport { CatsService } from './cats.service';\nimport { Cat } from './interfaces/cat.interface';\n\n@Controller('cats')\nexport class CatsController {\n constructor(private catsService: CatsService) {}\n\n @Get()\n async findAll(): Promise<Cat[]> {\n return this.catsService.findAll();\n }\n}\n"),e.qZA()(),e.TgZ(55,"pre")(56,"code",12),e._uU(57,"\nimport { Controller, Get, Bind, Dependencies } from '@nestjs/common';\nimport { CatsService } from './cats.service';\n\n@Controller('cats')\n@Dependencies(CatsService)\nexport class CatsController {\n constructor(catsService) {\n this.catsService = catsService;\n }\n\n @Get()\n async findAll() {\n return this.catsService.findAll();\n }\n}\n"),e.qZA()(),e.TgZ(58,"p"),e._uU(59,"Finally, we register the provider with the Nest IoC container:"),e.qZA(),e.TgZ(60,"span",10),e._uU(61),e.ALo(62,"extension"),e._UZ(63,"app-tabs",null,14),e.qZA(),e.TgZ(65,"pre")(66,"code",12),e._uU(67,"\nimport { Module } from '@nestjs/common';\nimport { CatsController } from './cats/cats.controller';\nimport { CatsService } from './cats/cats.service';\n\n@Module({\n controllers: [CatsController],\n providers: [CatsService],\n})\nexport class AppModule {}\n"),e.qZA()(),e.TgZ(68,"p"),e._uU(69,"What exactly is happening under the covers to make this work? There are three key steps in the process:"),e.qZA(),e.TgZ(70,"ol")(71,"li"),e._uU(72,"In "),e.TgZ(73,"code"),e._uU(74,"cats.service.ts"),e.qZA(),e._uU(75,", the "),e.TgZ(76,"code"),e._uU(77,"@Injectable()"),e.qZA(),e._uU(78," decorator declares the "),e.TgZ(79,"code"),e._uU(80,"CatsService"),e.qZA(),e._uU(81," class as a class that can be managed by the Nest IoC container."),e.qZA(),e.TgZ(82,"li"),e._uU(83,"In "),e.TgZ(84,"code"),e._uU(85,"cats.controller.ts"),e.qZA(),e._uU(86,", "),e.TgZ(87,"code"),e._uU(88,"CatsController"),e.qZA(),e._uU(89," declares a dependency on the "),e.TgZ(90,"code"),e._uU(91,"CatsService"),e.qZA(),e._uU(92," token with constructor injection:"),e.qZA()(),e.TgZ(93,"pre")(94,"code",12),e._uU(95,"\n constructor(private catsService: CatsService)\n"),e.qZA()(),e.TgZ(96,"ol",15)(97,"li"),e._uU(98,"In "),e.TgZ(99,"code"),e._uU(100,"app.module.ts"),e.qZA(),e._uU(101,", we associate the token "),e.TgZ(102,"code"),e._uU(103,"CatsService"),e.qZA(),e._uU(104," with the class "),e.TgZ(105,"code"),e._uU(106,"CatsService"),e.qZA(),e._uU(107," from the "),e.TgZ(108,"code"),e._uU(109,"cats.service.ts"),e.qZA(),e._uU(110," file. We'll "),e.TgZ(111,"a",16),e._uU(112,"see below"),e.qZA(),e._uU(113," exactly how this association (also called "),e.TgZ(114,"em"),e._uU(115,"registration"),e.qZA(),e._uU(116,") occurs."),e.qZA()(),e.TgZ(117,"p"),e._uU(118,"When the Nest IoC container instantiates a "),e.TgZ(119,"code"),e._uU(120,"CatsController"),e.qZA(),e._uU(121,", it first looks for any dependencies*. When it finds the "),e.TgZ(122,"code"),e._uU(123,"CatsService"),e.qZA(),e._uU(124," dependency, it performs a lookup on the "),e.TgZ(125,"code"),e._uU(126,"CatsService"),e.qZA(),e._uU(127," token, which returns the "),e.TgZ(128,"code"),e._uU(129,"CatsService"),e.qZA(),e._uU(130," class, per the registration step (#3 above). Assuming "),e.TgZ(131,"code"),e._uU(132,"SINGLETON"),e.qZA(),e._uU(133," scope (the default behavior), Nest will then either create an instance of "),e.TgZ(134,"code"),e._uU(135,"CatsService"),e.qZA(),e._uU(136,", cache it, and return it, or if one is already cached, return the existing instance."),e.qZA(),e.TgZ(137,"p"),e._uU(138,'*This explanation is a bit simplified to illustrate the point. One important area we glossed over is that the process of analyzing the code for dependencies is very sophisticated, and happens during application bootstrapping. One key feature is that dependency analysis (or "creating the dependency graph"), is '),e.TgZ(139,"strong"),e._uU(140,"transitive"),e.qZA(),e._uU(141,". In the above example, if the "),e.TgZ(142,"code"),e._uU(143,"CatsService"),e.qZA(),e._uU(144,' itself had dependencies, those too would be resolved. The dependency graph ensures that dependencies are resolved in the correct order - essentially "bottom up". This mechanism relieves the developer from having to manage such complex dependency graphs.'),e.qZA(),e.TgZ(145,"p"),e._UZ(146,"app-banner-courses"),e.qZA(),e.TgZ(147,"h4",17)(148,"span"),e._uU(149,"Standard providers"),e.qZA()(),e.TgZ(150,"p"),e._uU(151,"Let's take a closer look at the "),e.TgZ(152,"code"),e._uU(153,"@Module()"),e.qZA(),e._uU(154," decorator. In "),e.TgZ(155,"code"),e._uU(156,"app.module"),e.qZA(),e._uU(157,", we declare:"),e.qZA(),e.TgZ(158,"pre")(159,"code",12),e._uU(160,"\n@Module({\n controllers: [CatsController],\n providers: [CatsService],\n})\n"),e.qZA()(),e.TgZ(161,"p"),e._uU(162,"The "),e.TgZ(163,"code"),e._uU(164,"providers"),e.qZA(),e._uU(165," property takes an array of "),e.TgZ(166,"code"),e._uU(167,"providers"),e.qZA(),e._uU(168,". So far, we've supplied those providers via a list of class names. In fact, the syntax "),e.TgZ(169,"code"),e._uU(170,"providers: [CatsService]"),e.qZA(),e._uU(171," is short-hand for the more complete syntax:"),e.qZA(),e.TgZ(172,"pre")(173,"code",12),e._uU(174,"\nproviders: [\n {\n provide: CatsService,\n useClass: CatsService,\n },\n];\n"),e.qZA()(),e.TgZ(175,"p"),e._uU(176,"Now that we see this explicit construction, we can understand the registration process. Here, we are clearly associating the token "),e.TgZ(177,"code"),e._uU(178,"CatsService"),e.qZA(),e._uU(179," with the class "),e.TgZ(180,"code"),e._uU(181,"CatsService"),e.qZA(),e._uU(182,". The short-hand notation is merely a convenience to simplify the most common use-case, where the token is used to request an instance of a class by the same name."),e.qZA(),e.TgZ(183,"h4",18)(184,"span"),e._uU(185,"Custom providers"),e.qZA()(),e.TgZ(186,"p"),e._uU(187,"What happens when your requirements go beyond those offered by "),e.TgZ(188,"em"),e._uU(189,"Standard providers"),e.qZA(),e._uU(190,"? Here are a few examples:"),e.qZA(),e.TgZ(191,"ul")(192,"li"),e._uU(193,"You want to create a custom instance instead of having Nest instantiate (or return a cached instance of) a class"),e.qZA(),e.TgZ(194,"li"),e._uU(195,"You want to re-use an existing class in a second dependency"),e.qZA(),e.TgZ(196,"li"),e._uU(197,"You want to override a class with a mock version for testing"),e.qZA()(),e.TgZ(198,"p"),e._uU(199,"Nest allows you to define Custom providers to handle these cases. It provides several ways to define custom providers. Let's walk through them."),e.qZA(),e.TgZ(200,"blockquote",19)(201,"strong"),e._uU(202,"Hint"),e.qZA(),e._uU(203," If you are having problems with dependency resolution you can set the "),e.TgZ(204,"code"),e._uU(205,"NEST_DEBUG"),e.qZA(),e._uU(206," environment variable and get extra dependency resolution logs during startup.\n"),e.qZA(),e.TgZ(207,"h4",20)(208,"span"),e._uU(209,"Value providers: "),e.TgZ(210,"code"),e._uU(211,"useValue"),e.qZA()()(),e.TgZ(212,"p"),e._uU(213,"The "),e.TgZ(214,"code"),e._uU(215,"useValue"),e.qZA(),e._uU(216," syntax is useful for injecting a constant value, putting an external library into the Nest container, or replacing a real implementation with a mock object. Let's say you'd like to force Nest to use a mock "),e.TgZ(217,"code"),e._uU(218,"CatsService"),e.qZA(),e._uU(219," for testing purposes."),e.qZA(),e.TgZ(220,"pre")(221,"code",12),e._uU(222,"\nimport { CatsService } from './cats.service';\n\nconst mockCatsService = {\n /* mock implementation\n ...\n */\n};\n\n@Module({\n imports: [CatsModule],\n providers: [\n {\n provide: CatsService,\n useValue: mockCatsService,\n },\n ],\n})\nexport class AppModule {}\n"),e.qZA()(),e.TgZ(223,"p"),e._uU(224,"In this example, the "),e.TgZ(225,"code"),e._uU(226,"CatsService"),e.qZA(),e._uU(227," token will resolve to the "),e.TgZ(228,"code"),e._uU(229,"mockCatsService"),e.qZA(),e._uU(230," mock object. "),e.TgZ(231,"code"),e._uU(232,"useValue"),e.qZA(),e._uU(233," requires a value - in this case a literal object that has the same interface as the "),e.TgZ(234,"code"),e._uU(235,"CatsService"),e.qZA(),e._uU(236," class it is replacing. Because of TypeScript's "),e.TgZ(237,"a",21),e._uU(238,"structural typing"),e.qZA(),e._uU(239,", you can use any object that has a compatible interface, including a literal object or a class instance instantiated with "),e.TgZ(240,"code"),e._uU(241,"new"),e.qZA(),e._uU(242,"."),e.qZA(),e.TgZ(243,"h4",22)(244,"span"),e._uU(245,"Non-class-based provider tokens"),e.qZA()(),e.TgZ(246,"p"),e._uU(247,"So far, we've used class names as our provider tokens (the value of the "),e.TgZ(248,"code"),e._uU(249,"provide"),e.qZA(),e._uU(250," property in a provider listed in the "),e.TgZ(251,"code"),e._uU(252,"providers"),e.qZA(),e._uU(253," array). This is matched by the standard pattern used with "),e.TgZ(254,"a",6),e._uU(255,"constructor based injection"),e.qZA(),e._uU(256,", where the token is also a class name. (Refer back to "),e.TgZ(257,"a",23),e._uU(258,"DI Fundamentals"),e.qZA(),e._uU(259," for a refresher on tokens if this concept isn't entirely clear). Sometimes, we may want the flexibility to use strings or symbols as the DI token. For example:"),e.qZA(),e.TgZ(260,"pre")(261,"code",12),e._uU(262,"\nimport { connection } from './connection';\n\n@Module({\n providers: [\n {\n provide: 'CONNECTION',\n useValue: connection,\n },\n ],\n})\nexport class AppModule {}\n"),e.qZA()(),e.TgZ(263,"p"),e._uU(264,"In this example, we are associating a string-valued token ("),e.TgZ(265,"code"),e._uU(266,"'CONNECTION'"),e.qZA(),e._uU(267,") with a pre-existing "),e.TgZ(268,"code"),e._uU(269,"connection"),e.qZA(),e._uU(270," object we've imported from an external file."),e.qZA(),e.TgZ(271,"blockquote",24)(272,"strong"),e._uU(273,"Notice"),e.qZA(),e._uU(274," In addition to using strings as token values, you can also use JavaScript "),e.TgZ(275,"a",25),e._uU(276,"symbols"),e.qZA(),e._uU(277," or TypeScript "),e.TgZ(278,"a",26),e._uU(279,"enums"),e.qZA(),e._uU(280,".\n"),e.qZA(),e.TgZ(281,"p"),e._uU(282,"We've previously seen how to inject a provider using the standard "),e.TgZ(283,"a",6),e._uU(284,"constructor based injection"),e.qZA(),e._uU(285," pattern. This pattern "),e.TgZ(286,"strong"),e._uU(287,"requires"),e.qZA(),e._uU(288," that the dependency be declared with a class name. The "),e.TgZ(289,"code"),e._uU(290,"'CONNECTION'"),e.qZA(),e._uU(291," custom provider uses a string-valued token. Let's see how to inject such a provider. To do so, we use the "),e.TgZ(292,"code"),e._uU(293,"@Inject()"),e.qZA(),e._uU(294," decorator. This decorator takes a single argument - the token."),e.qZA(),e.TgZ(295,"span",10),e._UZ(296,"app-tabs",null,27),e.qZA(),e.TgZ(298,"pre")(299,"code",12),e._uU(300,"\n@Injectable()\nexport class CatsRepository {\n constructor(@Inject('CONNECTION') connection: Connection) {}\n}\n"),e.qZA()(),e.TgZ(301,"pre")(302,"code",12),e._uU(303,"\n@Injectable()\n@Dependencies('CONNECTION')\nexport class CatsRepository {\n constructor(connection) {}\n}\n"),e.qZA()(),e.TgZ(304,"blockquote",19)(305,"strong"),e._uU(306,"Hint"),e.qZA(),e._uU(307," The "),e.TgZ(308,"code"),e._uU(309,"@Inject()"),e.qZA(),e._uU(310," decorator is imported from "),e.TgZ(311,"code"),e._uU(312,"@nestjs/common"),e.qZA(),e._uU(313," package.\n"),e.qZA(),e.TgZ(314,"p"),e._uU(315,"While we directly use the string "),e.TgZ(316,"code"),e._uU(317,"'CONNECTION'"),e.qZA(),e._uU(318," in the above examples for illustration purposes, for clean code organization, it's best practice to define tokens in a separate file, such as "),e.TgZ(319,"code"),e._uU(320,"constants.ts"),e.qZA(),e._uU(321,". Treat them much as you would symbols or enums that are defined in their own file and imported where needed."),e.qZA(),e.TgZ(322,"h4",28)(323,"span"),e._uU(324,"Class providers: "),e.TgZ(325,"code"),e._uU(326,"useClass"),e.qZA()()(),e.TgZ(327,"p"),e._uU(328,"The "),e.TgZ(329,"code"),e._uU(330,"useClass"),e.qZA(),e._uU(331," syntax allows you to dynamically determine a class that a token should resolve to. For example, suppose we have an abstract (or default) "),e.TgZ(332,"code"),e._uU(333,"ConfigService"),e.qZA(),e._uU(334," class. Depending on the current environment, we want Nest to provide a different implementation of the configuration service. The following code implements such a strategy."),e.qZA(),e.TgZ(335,"pre")(336,"code",12),e._uU(337,"\nconst configServiceProvider = {\n provide: ConfigService,\n useClass:\n process.env.NODE_ENV === 'development'\n ? DevelopmentConfigService\n : ProductionConfigService,\n};\n\n@Module({\n providers: [configServiceProvider],\n})\nexport class AppModule {}\n"),e.qZA()(),e.TgZ(338,"p"),e._uU(339,"Let's look at a couple of details in this code sample. You'll notice that we define "),e.TgZ(340,"code"),e._uU(341,"configServiceProvider"),e.qZA(),e._uU(342," with a literal object first, then pass it in the module decorator's "),e.TgZ(343,"code"),e._uU(344,"providers"),e.qZA(),e._uU(345," property. This is just a bit of code organization, but is functionally equivalent to the examples we've used thus far in this chapter."),e.qZA(),e.TgZ(346,"p"),e._uU(347,"Also, we have used the "),e.TgZ(348,"code"),e._uU(349,"ConfigService"),e.qZA(),e._uU(350," class name as our token. For any class that depends on "),e.TgZ(351,"code"),e._uU(352,"ConfigService"),e.qZA(),e._uU(353,", Nest will inject an instance of the provided class ("),e.TgZ(354,"code"),e._uU(355,"DevelopmentConfigService"),e.qZA(),e._uU(356," or "),e.TgZ(357,"code"),e._uU(358,"ProductionConfigService"),e.qZA(),e._uU(359,") overriding any default implementation that may have been declared elsewhere (e.g., a "),e.TgZ(360,"code"),e._uU(361,"ConfigService"),e.qZA(),e._uU(362," declared with an "),e.TgZ(363,"code"),e._uU(364,"@Injectable()"),e.qZA(),e._uU(365," decorator)."),e.qZA(),e.TgZ(366,"h4",29)(367,"span"),e._uU(368,"Factory providers: "),e.TgZ(369,"code"),e._uU(370,"useFactory"),e.qZA()()(),e.TgZ(371,"p"),e._uU(372,"The "),e.TgZ(373,"code"),e._uU(374,"useFactory"),e.qZA(),e._uU(375," syntax allows for creating providers "),e.TgZ(376,"strong"),e._uU(377,"dynamically"),e.qZA(),e._uU(378,". The actual provider will be supplied by the value returned from a factory function. The factory function can be as simple or complex as needed. A simple factory may not depend on any other providers. A more complex factory can itself inject other providers it needs to compute its result. For the latter case, the factory provider syntax has a pair of related mechanisms:"),e.qZA(),e.TgZ(379,"ol")(380,"li"),e._uU(381,"The factory function can accept (optional) arguments."),e.qZA(),e.TgZ(382,"li"),e._uU(383,"The (optional) "),e.TgZ(384,"code"),e._uU(385,"inject"),e.qZA(),e._uU(386," property accepts an array of providers that Nest will resolve and pass as arguments to the factory function during the instantiation process. Also, these providers can be marked as optional. The two lists should be correlated: Nest will pass instances from the "),e.TgZ(387,"code"),e._uU(388,"inject"),e.qZA(),e._uU(389," list as arguments to the factory function in the same order. The example below demonstrates this."),e.qZA()(),e.TgZ(390,"span",10),e._UZ(391,"app-tabs",null,30),e.qZA(),e.TgZ(393,"pre")(394,"code",12),e._uU(395,"\nconst connectionProvider = {\n provide: 'CONNECTION',\n useFactory: (optionsProvider: OptionsProvider, optionalProvider?: string) => {\n const options = optionsProvider.get();\n return new DatabaseConnection(options);\n },\n inject: [OptionsProvider, { token: 'SomeOptionalProvider', optional: true }],\n // \\_____________/ \\__________________/\n // This provider The provider with this\n // is mandatory. token can resolve to `undefined`.\n};\n\n@Module({\n providers: [\n connectionProvider,\n OptionsProvider,\n // { provide: 'SomeOptionalProvider', useValue: 'anything' },\n ],\n})\nexport class AppModule {}\n"),e.qZA()(),e.TgZ(396,"pre")(397,"code",12),e._uU(398,"\nconst connectionProvider = {\n provide: 'CONNECTION',\n useFactory: (optionsProvider, optionalProvider) => {\n const options = optionsProvider.get();\n return new DatabaseConnection(options);\n },\n inject: [OptionsProvider, { token: 'SomeOptionalProvider', optional: true }],\n // \\_____________/ \\__________________/\n // This provider The provider with this\n // is mandatory. token can resolve to `undefined`.\n};\n\n@Module({\n providers: [\n connectionProvider,\n OptionsProvider,\n // { provide: 'SomeOptionalProvider', useValue: 'anything' },\n ],\n})\nexport class AppModule {}\n"),e.qZA()(),e.TgZ(399,"h4",31)(400,"span"),e._uU(401,"Alias providers: "),e.TgZ(402,"code"),e._uU(403,"useExisting"),e.qZA()()(),e.TgZ(404,"p"),e._uU(405,"The "),e.TgZ(406,"code"),e._uU(407,"useExisting"),e.qZA(),e._uU(408," syntax allows you to create aliases for existing providers. This creates two ways to access the same provider. In the example below, the (string-based) token "),e.TgZ(409,"code"),e._uU(410,"'AliasedLoggerService'"),e.qZA(),e._uU(411," is an alias for the (class-based) token "),e.TgZ(412,"code"),e._uU(413,"LoggerService"),e.qZA(),e._uU(414,". Assume we have two different dependencies, one for "),e.TgZ(415,"code"),e._uU(416,"'AliasedLoggerService'"),e.qZA(),e._uU(417," and one for "),e.TgZ(418,"code"),e._uU(419,"LoggerService"),e.qZA(),e._uU(420,". If both dependencies are specified with "),e.TgZ(421,"code"),e._uU(422,"SINGLETON"),e.qZA(),e._uU(423," scope, they'll both resolve to the same instance."),e.qZA(),e.TgZ(424,"pre")(425,"code",12),e._uU(426,"\n@Injectable()\nclass LoggerService {\n /* implementation details */\n}\n\nconst loggerAliasProvider = {\n provide: 'AliasedLoggerService',\n useExisting: LoggerService,\n};\n\n@Module({\n providers: [LoggerService, loggerAliasProvider],\n})\nexport class AppModule {}\n"),e.qZA()(),e.TgZ(427,"h4",32)(428,"span"),e._uU(429,"Non-service based providers"),e.qZA()(),e.TgZ(430,"p"),e._uU(431,"While providers often supply services, they are not limited to that usage. A provider can supply "),e.TgZ(432,"strong"),e._uU(433,"any"),e.qZA(),e._uU(434," value. For example, a provider may supply an array of configuration objects based on the current environment, as shown below:"),e.qZA(),e.TgZ(435,"pre")(436,"code",12),e._uU(437,"\nconst configFactory = {\n provide: 'CONFIG',\n useFactory: () => {\n return process.env.NODE_ENV === 'development' ? devConfig : prodConfig;\n },\n};\n\n@Module({\n providers: [configFactory],\n})\nexport class AppModule {}\n"),e.qZA()(),e.TgZ(438,"h4",33)(439,"span"),e._uU(440,"Export custom provider"),e.qZA()(),e.TgZ(441,"p"),e._uU(442,"Like any provider, a custom provider is scoped to its declaring module. To make it visible to other modules, it must be exported. To export a custom provider, we can either use its token or the full provider object."),e.qZA(),e.TgZ(443,"p"),e._uU(444,"The following example shows exporting using the token:"),e.qZA(),e.TgZ(445,"span",10),e._UZ(446,"app-tabs",null,34),e.qZA(),e.TgZ(448,"pre")(449,"code",12),e._uU(450,"\nconst connectionFactory = {\n provide: 'CONNECTION',\n useFactory: (optionsProvider: OptionsProvider) => {\n const options = optionsProvider.get();\n return new DatabaseConnection(options);\n },\n inject: [OptionsProvider],\n};\n\n@Module({\n providers: [connectionFactory],\n exports: ['CONNECTION'],\n})\nexport class AppModule {}\n"),e.qZA()(),e.TgZ(451,"pre")(452,"code",12),e._uU(453,"\nconst connectionFactory = {\n provide: 'CONNECTION',\n useFactory: (optionsProvider) => {\n const options = optionsProvider.get();\n return new DatabaseConnection(options);\n },\n inject: [OptionsProvider],\n};\n\n@Module({\n providers: [connectionFactory],\n exports: ['CONNECTION'],\n})\nexport class AppModule {}\n"),e.qZA()(),e.TgZ(454,"p"),e._uU(455,"Alternatively, export with the full provider object:"),e.qZA(),e.TgZ(456,"span",10),e._UZ(457,"app-tabs",null,35),e.qZA(),e.TgZ(459,"pre")(460,"code",12),e._uU(461,"\nconst connectionFactory = {\n provide: 'CONNECTION',\n useFactory: (optionsProvider: OptionsProvider) => {\n const options = optionsProvider.get();\n return new DatabaseConnection(options);\n },\n inject: [OptionsProvider],\n};\n\n@Module({\n providers: [connectionFactory],\n exports: [connectionFactory],\n})\nexport class AppModule {}\n"),e.qZA()(),e.TgZ(462,"pre")(463,"code",12),e._uU(464,"\nconst connectionFactory = {\n provide: 'CONNECTION',\n useFactory: (optionsProvider) => {\n const options = optionsProvider.get();\n return new DatabaseConnection(options);\n },\n inject: [OptionsProvider],\n};\n\n@Module({\n providers: [connectionFactory],\n exports: [connectionFactory],\n})\nexport class AppModule {}\n"),e.qZA()()()),2&n){const a=e.MAs(38),r=e.MAs(51),i=e.MAs(64),u=e.MAs(297),_=e.MAs(392),g=e.MAs(447),Z=e.MAs(458);e.xp6(35),e.hij(" ",e.xi3(36,27,"cats.service",a.isJsActive),"\n"),e.xp6(4),e.ekj("hide",a.isJsActive),e.xp6(3),e.ekj("hide",!a.isJsActive),e.xp6(6),e.hij(" ",e.xi3(49,30,"cats.controller",r.isJsActive),"\n"),e.xp6(4),e.ekj("hide",r.isJsActive),e.xp6(3),e.ekj("hide",!r.isJsActive),e.xp6(6),e.hij(" ",e.xi3(62,33,"app.module",i.isJsActive),"\n"),e.xp6(237),e.ekj("hide",u.isJsActive),e.xp6(3),e.ekj("hide",!u.isJsActive),e.xp6(92),e.ekj("hide",_.isJsActive),e.xp6(3),e.ekj("hide",!_.isJsActive),e.xp6(52),e.ekj("hide",g.isJsActive),e.xp6(3),e.ekj("hide",!g.isJsActive),e.xp6(8),e.ekj("hide",Z.isJsActive),e.xp6(3),e.ekj("hide",!Z.isJsActive)}},dependencies:[h.n,l.U,m.f,U.F],encapsulation:2,changeDetection:0})}return t})();var v=c(2936);let k=(()=>{class t extends d.y{static \u0275fac=function(){let o;return function(s){return(o||(o=e.n5z(t)))(s||t)}}();static \u0275cmp=e.Xpm({type:t,selectors:[["app-dynamic-modules"]],features:[e.qOj],decls:888,vars:28,consts:[[1,"content"],["contentReference",""],[1,"github-links"],["href","https://github.com/ChuTingzj/docs.nestjs.zh-cn.com/tree/master/content/fundamentals/dynamic-modules.md","aria-label","Suggest Edits","title","Suggest Edits"],[1,"fas","fa-edit"],["id","dynamic-modules"],["routerLink","/modules"],["rel","nofollow","target","_blank","href","https://docs.nestjs.com/modules#dynamic-modules"],["appAnchor","","id","introduction"],["routerLink","/providers"],["routerLink","/controllers"],[1,"language-typescript"],["rel","nofollow","target","_blank","href","https://docs.nestjs.com/fundamentals/custom-providers"],["appAnchor","","id","dynamic-module-use-case"],["appAnchor","","id","config-module-example"],["rel","nofollow","target","_blank","href","https://docs.nestjs.com/techniques/configuration#service"],["rel","nofollow","target","_blank","href","https://github.com/nestjs/nest/tree/master/sample/25-dynamic-modules"],[1,"info"],["appAnchor","","id","module-configuration"],["rel","nofollow","target","_blank","href","https://docs.nestjs.com/fundamentals/custom-providers#non-service-based-providers"],["rel","nofollow","target","_blank","href","https://docs.nestjs.com/fundamentals/custom-providers#non-class-based-provider-tokens"],["appAnchor","","id","example"],["appAnchor","","id","community-guidelines"],["appAnchor","","id","configurable-module-builder"],[1,"filename"],["app06539e568b1a0383d9915d106630f489181a94de",""],["appAnchor","","id","custom-method-key"],["appc6c08661ee568d9d3c1544d7edfcfb9e5b2af8cd",""],["appAnchor","","id","custom-options-factory-class"],["app77ec6606fd4e43e2c3321b3da5ae893715cf3a84",""],["appAnchor","","id","extra-options"],["href","/modules#dynamic-modules"],["appAnchor","","id","extending-auto-generated-methods"]],template:function(n,s){if(1&n&&(e.TgZ(0,"div",0,1)(2,"div",2)(3,"a",3),e._UZ(4,"i",4),e.qZA()(),e.TgZ(5,"h3",5),e._uU(6,"Dynamic modules"),e.qZA(),e.TgZ(7,"p"),e._uU(8,"The "),e.TgZ(9,"a",6),e._uU(10,"Modules chapter"),e.qZA(),e._uU(11," covers the basics of Nest modules, and includes a brief introduction to "),e.TgZ(12,"a",7),e._uU(13,"dynamic modules"),e.qZA(),e._uU(14,". This chapter expands on the subject of dynamic modules. Upon completion, you should have a good grasp of what they are and how and when to use them."),e.qZA(),e.TgZ(15,"h4",8)(16,"span"),e._uU(17,"Introduction"),e.qZA()(),e.TgZ(18,"p"),e._uU(19,"Most application code examples in the "),e.TgZ(20,"strong"),e._uU(21,"Overview"),e.qZA(),e._uU(22," section of the documentation make use of regular, or static, modules. Modules define groups of components like "),e.TgZ(23,"a",9),e._uU(24,"providers"),e.qZA(),e._uU(25," and "),e.TgZ(26,"a",10),e._uU(27,"controllers"),e.qZA(),e._uU(28," that fit together as a modular part of an overall application. They provide an execution context, or scope, for these components. For example, providers defined in a module are visible to other members of the module without the need to export them. When a provider needs to be visible outside of a module, it is first exported from its host module, and then imported into its consuming module."),e.qZA(),e.TgZ(29,"p"),e._uU(30,"Let's walk through a familiar example."),e.qZA(),e.TgZ(31,"p"),e._uU(32,"First, we'll define a "),e.TgZ(33,"code"),e._uU(34,"UsersModule"),e.qZA(),e._uU(35," to provide and export a "),e.TgZ(36,"code"),e._uU(37,"UsersService"),e.qZA(),e._uU(38,". "),e.TgZ(39,"code"),e._uU(40,"UsersModule"),e.qZA(),e._uU(41," is the "),e.TgZ(42,"strong"),e._uU(43,"host"),e.qZA(),e._uU(44," module for "),e.TgZ(45,"code"),e._uU(46,"UsersService"),e.qZA(),e._uU(47,"."),e.qZA(),e.TgZ(48,"pre")(49,"code",11),e._uU(50,"\nimport { Module } from '@nestjs/common';\nimport { UsersService } from './users.service';\n\n@Module({\n providers: [UsersService],\n exports: [UsersService],\n})\nexport class UsersModule {}\n"),e.qZA()(),e.TgZ(51,"p"),e._uU(52,"Next, we'll define an "),e.TgZ(53,"code"),e._uU(54,"AuthModule"),e.qZA(),e._uU(55,", which imports "),e.TgZ(56,"code"),e._uU(57,"UsersModule"),e.qZA(),e._uU(58,", making "),e.TgZ(59,"code"),e._uU(60,"UsersModule"),e.qZA(),e._uU(61,"'s exported providers available inside "),e.TgZ(62,"code"),e._uU(63,"AuthModule"),e.qZA(),e._uU(64,":"),e.qZA(),e.TgZ(65,"pre")(66,"code",11),e._uU(67,"\nimport { Module } from '@nestjs/common';\nimport { AuthService } from './auth.service';\nimport { UsersModule } from '../users/users.module';\n\n@Module({\n imports: [UsersModule],\n providers: [AuthService],\n exports: [AuthService],\n})\nexport class AuthModule {}\n"),e.qZA()(),e.TgZ(68,"p"),e._uU(69,"These constructs allow us to inject "),e.TgZ(70,"code"),e._uU(71,"UsersService"),e.qZA(),e._uU(72," in, for example, the "),e.TgZ(73,"code"),e._uU(74,"AuthService"),e.qZA(),e._uU(75," that is hosted in "),e.TgZ(76,"code"),e._uU(77,"AuthModule"),e.qZA(),e._uU(78,":"),e.qZA(),e.TgZ(79,"pre")(80,"code",11),e._uU(81,"\nimport { Injectable } from '@nestjs/common';\nimport { UsersService } from '../users/users.service';\n\n@Injectable()\nexport class AuthService {\n constructor(private usersService: UsersService) {}\n /*\n Implementation that makes use of this.usersService\n */\n}\n"),e.qZA()(),e.TgZ(82,"p"),e._uU(83,"We'll refer to this as "),e.TgZ(84,"strong"),e._uU(85,"static"),e.qZA(),e._uU(86," module binding. All the information Nest needs to wire together the modules has already been declared in the host and consuming modules. Let's unpack what's happening during this process. Nest makes "),e.TgZ(87,"code"),e._uU(88,"UsersService"),e.qZA(),e._uU(89," available inside "),e.TgZ(90,"code"),e._uU(91,"AuthModule"),e.qZA(),e._uU(92," by:"),e.qZA(),e.TgZ(93,"ol")(94,"li"),e._uU(95,"Instantiating "),e.TgZ(96,"code"),e._uU(97,"UsersModule"),e.qZA(),e._uU(98,", including transitively importing other modules that "),e.TgZ(99,"code"),e._uU(100,"UsersModule"),e.qZA(),e._uU(101," itself consumes, and transitively resolving any dependencies (see "),e.TgZ(102,"a",12),e._uU(103,"Custom providers"),e.qZA(),e._uU(104,")."),e.qZA(),e.TgZ(105,"li"),e._uU(106,"Instantiating "),e.TgZ(107,"code"),e._uU(108,"AuthModule"),e.qZA(),e._uU(109,", and making "),e.TgZ(110,"code"),e._uU(111,"UsersModule"),e.qZA(),e._uU(112,"'s exported providers available to components in "),e.TgZ(113,"code"),e._uU(114,"AuthModule"),e.qZA(),e._uU(115," (just as if they had been declared in "),e.TgZ(116,"code"),e._uU(117,"AuthModule"),e.qZA(),e._uU(118,")."),e.qZA(),e.TgZ(119,"li"),e._uU(120,"Injecting an instance of "),e.TgZ(121,"code"),e._uU(122,"UsersService"),e.qZA(),e._uU(123," in "),e.TgZ(124,"code"),e._uU(125,"AuthService"),e.qZA(),e._uU(126,"."),e.qZA()(),e.TgZ(127,"h4",13)(128,"span"),e._uU(129,"Dynamic module use case"),e.qZA()(),e.TgZ(130,"p"),e._uU(131,"With static module binding, there's no opportunity for the consuming module to "),e.TgZ(132,"strong"),e._uU(133,"influence"),e.qZA(),e._uU(134,' how providers from the host module are configured. Why does this matter? Consider the case where we have a general purpose module that needs to behave differently in different use cases. This is analogous to the concept of a "plugin" in many systems, where a generic facility requires some configuration before it can be used by a consumer.'),e.qZA(),e.TgZ(135,"p"),e._uU(136,"A good example with Nest is a "),e.TgZ(137,"strong"),e._uU(138,"configuration module"),e.qZA(),e._uU(139,". Many applications find it useful to externalize configuration details by using a configuration module. This makes it easy to dynamically change the application settings in different deployments: e.g., a development database for developers, a staging database for the staging/testing environment, etc. By delegating the management of configuration parameters to a configuration module, the application source code remains independent of configuration parameters."),e.qZA(),e.TgZ(140,"p"),e._uU(141,'The challenge is that the configuration module itself, since it\'s generic (similar to a "plugin"), needs to be customized by its consuming module. This is where '),e.TgZ(142,"em"),e._uU(143,"dynamic modules"),e.qZA(),e._uU(144," come into play. Using dynamic module features, we can make our configuration module "),e.TgZ(145,"strong"),e._uU(146,"dynamic"),e.qZA(),e._uU(147," so that the consuming module can use an API to control how the configuration module is customized at the time it is imported."),e.qZA(),e.TgZ(148,"p"),e._uU(149,"In other words, dynamic modules provide an API for importing one module into another, and customizing the properties and behavior of that module when it is imported, as opposed to using the static bindings we've seen so far."),e.qZA(),e.TgZ(150,"p"),e._UZ(151,"app-banner-devtools"),e.qZA(),e.TgZ(152,"h4",14)(153,"span"),e._uU(154,"Config module example"),e.qZA()(),e.TgZ(155,"p"),e._uU(156,"We'll be using the basic version of the example code from the "),e.TgZ(157,"a",15),e._uU(158,"configuration chapter"),e.qZA(),e._uU(159," for this section. The completed version as of the end of this chapter is available as a working "),e.TgZ(160,"a",16),e._uU(161,"example here"),e.qZA(),e._uU(162,"."),e.qZA(),e.TgZ(163,"p"),e._uU(164,"Our requirement is to make "),e.TgZ(165,"code"),e._uU(166,"ConfigModule"),e.qZA(),e._uU(167," accept an "),e.TgZ(168,"code"),e._uU(169,"options"),e.qZA(),e._uU(170," object to customize it. Here's the feature we want to support. The basic sample hard-codes the location of the "),e.TgZ(171,"code"),e._uU(172,".env"),e.qZA(),e._uU(173," file to be in the project root folder. Let's suppose we want to make that configurable, such that you can manage your "),e.TgZ(174,"code"),e._uU(175,".env"),e.qZA(),e._uU(176," files in any folder of your choosing. For example, imagine you want to store your various "),e.TgZ(177,"code"),e._uU(178,".env"),e.qZA(),e._uU(179," files in a folder under the project root called "),e.TgZ(180,"code"),e._uU(181,"config"),e.qZA(),e._uU(182," (i.e., a sibling folder to "),e.TgZ(183,"code"),e._uU(184,"src"),e.qZA(),e._uU(185,"). You'd like to be able to choose different folders when using the "),e.TgZ(186,"code"),e._uU(187,"ConfigModule"),e.qZA(),e._uU(188," in different projects."),e.qZA(),e.TgZ(189,"p"),e._uU(190,"Dynamic modules give us the ability to pass parameters into the module being imported so we can change its behavior. 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. First, let's quickly review the example of "),e.TgZ(191,"em"),e._uU(192,"statically"),e.qZA(),e._uU(193," importing the "),e.TgZ(194,"code"),e._uU(195,"ConfigModule"),e.qZA(),e._uU(196," (i.e., an approach which has no ability to influence the behavior of the imported module). Pay close attention to the "),e.TgZ(197,"code"),e._uU(198,"imports"),e.qZA(),e._uU(199," array in the "),e.TgZ(200,"code"),e._uU(201,"@Module()"),e.qZA(),e._uU(202," decorator:"),e.qZA(),e.TgZ(203,"pre")(204,"code",11),e._uU(205,"\nimport { Module } from '@nestjs/common';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { ConfigModule } from './config/config.module';\n\n@Module({\n imports: [ConfigModule],\n controllers: [AppController],\n providers: [AppService],\n})\nexport class AppModule {}\n"),e.qZA()(),e.TgZ(206,"p"),e._uU(207,"Let's consider what a "),e.TgZ(208,"em"),e._uU(209,"dynamic module"),e.qZA(),e._uU(210," import, where we're passing in a configuration object, might look like. Compare the difference in the "),e.TgZ(211,"code"),e._uU(212,"imports"),e.qZA(),e._uU(213," array between these two examples:"),e.qZA(),e.TgZ(214,"pre")(215,"code",11),e._uU(216,"\nimport { Module } from '@nestjs/common';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { ConfigModule } from './config/config.module';\n\n@Module({\n imports: [ConfigModule.register({ folder: './config' })],\n controllers: [AppController],\n providers: [AppService],\n})\nexport class AppModule {}\n"),e.qZA()(),e.TgZ(217,"p"),e._uU(218,"Let's see what's happening in the dynamic example above. What are the moving parts?"),e.qZA(),e.TgZ(219,"ol")(220,"li")(221,"code"),e._uU(222,"ConfigModule"),e.qZA(),e._uU(223," is a normal class, so we can infer that it must have a "),e.TgZ(224,"strong"),e._uU(225,"static method"),e.qZA(),e._uU(226," called "),e.TgZ(227,"code"),e._uU(228,"register()"),e.qZA(),e._uU(229,". We know it's static because we're calling it on the "),e.TgZ(230,"code"),e._uU(231,"ConfigModule"),e.qZA(),e._uU(232," class, not on an "),e.TgZ(233,"strong"),e._uU(234,"instance"),e.qZA(),e._uU(235," of the class. Note: this method, which we will create soon, can have any arbitrary name, but by convention we should call it either "),e.TgZ(236,"code"),e._uU(237,"forRoot()"),e.qZA(),e._uU(238," or "),e.TgZ(239,"code"),e._uU(240,"register()"),e.qZA(),e._uU(241,"."),e.qZA(),e.TgZ(242,"li"),e._uU(243,"The "),e.TgZ(244,"code"),e._uU(245,"register()"),e.qZA(),e._uU(246," method is defined by us, so we can accept any input arguments we like. In this case, we're going to accept a simple "),e.TgZ(247,"code"),e._uU(248,"options"),e.qZA(),e._uU(249," object with suitable properties, which is the typical case."),e.qZA(),e.TgZ(250,"li"),e._uU(251,"We can infer that the "),e.TgZ(252,"code"),e._uU(253,"register()"),e.qZA(),e._uU(254," method must return something like a "),e.TgZ(255,"code"),e._uU(256,"module"),e.qZA(),e._uU(257," since its return value appears in the familiar "),e.TgZ(258,"code"),e._uU(259,"imports"),e.qZA(),e._uU(260," list, which we've seen so far includes a list of modules."),e.qZA()(),e.TgZ(261,"p"),e._uU(262,"In fact, what our "),e.TgZ(263,"code"),e._uU(264,"register()"),e.qZA(),e._uU(265," method will return is a "),e.TgZ(266,"code"),e._uU(267,"DynamicModule"),e.qZA(),e._uU(268,". A dynamic module is nothing more than a module created at run-time, with the same exact properties as a static module, plus one additional property called "),e.TgZ(269,"code"),e._uU(270,"module"),e.qZA(),e._uU(271,". Let's quickly review a sample static module declaration, paying close attention to the module options passed in to the decorator:"),e.qZA(),e.TgZ(272,"pre")(273,"code",11),e._uU(274,"\n@Module({\n imports: [DogsModule],\n controllers: [CatsController],\n providers: [CatsService],\n exports: [CatsService]\n})\n"),e.qZA()(),e.TgZ(275,"p"),e._uU(276,"Dynamic modules must return an object with the exact same interface, plus one additional property called "),e.TgZ(277,"code"),e._uU(278,"module"),e.qZA(),e._uU(279,". The "),e.TgZ(280,"code"),e._uU(281,"module"),e.qZA(),e._uU(282," property serves as the name of the module, and should be the same as the class name of the module, as shown in the example below."),e.qZA(),e.TgZ(283,"blockquote",17)(284,"strong"),e._uU(285,"Hint"),e.qZA(),e._uU(286," For a dynamic module, all properties of the module options object are optional "),e.TgZ(287,"strong"),e._uU(288,"except"),e.qZA(),e.TgZ(289,"code"),e._uU(290,"module"),e.qZA(),e._uU(291,".\n"),e.qZA(),e.TgZ(292,"p"),e._uU(293,"What about the static "),e.TgZ(294,"code"),e._uU(295,"register()"),e.qZA(),e._uU(296," method? We can now see that its job is to return an object that has the "),e.TgZ(297,"code"),e._uU(298,"DynamicModule"),e.qZA(),e._uU(299," interface. When we call it, we are effectively providing a module to the "),e.TgZ(300,"code"),e._uU(301,"imports"),e.qZA(),e._uU(302," list, similar to the way we would do so in the static case by listing a module class name. In other words, the dynamic module API simply returns a module, but rather than fix the properties in the "),e.TgZ(303,"code"),e._uU(304,"@Module"),e.qZA(),e._uU(305," decorator, we specify them programmatically."),e.qZA(),e.TgZ(306,"p"),e._uU(307,"There are still a couple of details to cover to help make the picture complete:"),e.qZA(),e.TgZ(308,"ol")(309,"li"),e._uU(310,"We can now state that the "),e.TgZ(311,"code"),e._uU(312,"@Module()"),e.qZA(),e._uU(313," decorator's "),e.TgZ(314,"code"),e._uU(315,"imports"),e.qZA(),e._uU(316," property can take not only a module class name (e.g., "),e.TgZ(317,"code"),e._uU(318,"imports: [UsersModule]"),e.qZA(),e._uU(319,"), but also a function "),e.TgZ(320,"strong"),e._uU(321,"returning"),e.qZA(),e._uU(322," a dynamic module (e.g., "),e.TgZ(323,"code"),e._uU(324,"imports: [ConfigModule.register(...)]"),e.qZA(),e._uU(325,")."),e.qZA(),e.TgZ(326,"li"),e._uU(327,"A dynamic module can itself import other modules. We won't do so in this example, but if the dynamic module depends on providers from other modules, you would import them using the optional "),e.TgZ(328,"code"),e._uU(329,"imports"),e.qZA(),e._uU(330," property. Again, this is exactly analogous to the way you'd declare metadata for a static module using the "),e.TgZ(331,"code"),e._uU(332,"@Module()"),e.qZA(),e._uU(333," decorator."),e.qZA()(),e.TgZ(334,"p"),e._uU(335,"Armed with this understanding, we can now look at what our dynamic "),e.TgZ(336,"code"),e._uU(337,"ConfigModule"),e.qZA(),e._uU(338," declaration must look like. Let's take a crack at it."),e.qZA(),e.TgZ(339,"pre")(340,"code",11),e._uU(341,"\nimport { DynamicModule, Module } from '@nestjs/common';\nimport { ConfigService } from './config.service';\n\n@Module({})\nexport class ConfigModule {\n static register(): DynamicModule {\n return {\n module: ConfigModule,\n providers: [ConfigService],\n exports: [ConfigService],\n };\n }\n}\n"),e.qZA()(),e.TgZ(342,"p"),e._uU(343,"It should now be clear how the pieces tie together. Calling "),e.TgZ(344,"code"),e._uU(345,"ConfigModule.register(...)"),e.qZA(),e._uU(346," returns a "),e.TgZ(347,"code"),e._uU(348,"DynamicModule"),e.qZA(),e._uU(349," object with properties which are essentially the same as those that, until now, we've provided as metadata via the "),e.TgZ(350,"code"),e._uU(351,"@Module()"),e.qZA(),e._uU(352," decorator."),e.qZA(),e.TgZ(353,"blockquote",17)(354,"strong"),e._uU(355,"Hint"),e.qZA(),e._uU(356," Import "),e.TgZ(357,"code"),e._uU(358,"DynamicModule"),e.qZA(),e._uU(359," from "),e.TgZ(360,"code"),e._uU(361,"@nestjs/common"),e.qZA(),e._uU(362,".\n"),e.qZA(),e.TgZ(363,"p"),e._uU(364,"Our dynamic module isn't very interesting yet, however, as we haven't introduced any capability to "),e.TgZ(365,"strong"),e._uU(366,"configure"),e.qZA(),e._uU(367," it as we said we would like to do. Let's address that next."),e.qZA(),e.TgZ(368,"h4",18)(369,"span"),e._uU(370,"Module configuration"),e.qZA()(),e.TgZ(371,"p"),e._uU(372,"The obvious solution for customizing the behavior of the "),e.TgZ(373,"code"),e._uU(374,"ConfigModule"),e.qZA(),e._uU(375," is to pass it an "),e.TgZ(376,"code"),e._uU(377,"options"),e.qZA(),e._uU(378," object in the static "),e.TgZ(379,"code"),e._uU(380,"register()"),e.qZA(),e._uU(381," method, as we guessed above. Let's look once again at our consuming module's "),e.TgZ(382,"code"),e._uU(383,"imports"),e.qZA(),e._uU(384," property:"),e.qZA(),e.TgZ(385,"pre")(386,"code",11),e._uU(387,"\nimport { Module } from '@nestjs/common';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { ConfigModule } from './config/config.module';\n\n@Module({\n imports: [ConfigModule.register({ folder: './config' })],\n controllers: [AppController],\n providers: [AppService],\n})\nexport class AppModule {}\n"),e.qZA()(),e.TgZ(388,"p"),e._uU(389,"That nicely handles passing an "),e.TgZ(390,"code"),e._uU(391,"options"),e.qZA(),e._uU(392," object to our dynamic module. How do we then use that "),e.TgZ(393,"code"),e._uU(394,"options"),e.qZA(),e._uU(395," object in the "),e.TgZ(396,"code"),e._uU(397,"ConfigModule"),e.qZA(),e._uU(398,"? Let's consider that for a minute. We know that our "),e.TgZ(399,"code"),e._uU(400,"ConfigModule"),e.qZA(),e._uU(401," is basically a host for providing and exporting an injectable service - the "),e.TgZ(402,"code"),e._uU(403,"ConfigService"),e.qZA(),e._uU(404," - for use by other providers. It's actually our "),e.TgZ(405,"code"),e._uU(406,"ConfigService"),e.qZA(),e._uU(407," that needs to read the "),e.TgZ(408,"code"),e._uU(409,"options"),e.qZA(),e._uU(410," object to customize its behavior. Let's assume for the moment that we know how to somehow get the "),e.TgZ(411,"code"),e._uU(412,"options"),e.qZA(),e._uU(413," from the "),e.TgZ(414,"code"),e._uU(415,"register()"),e.qZA(),e._uU(416," method into the "),e.TgZ(417,"code"),e._uU(418,"ConfigService"),e.qZA(),e._uU(419,". With that assumption, we can make a few changes to the service to customize its behavior based on the properties from the "),e.TgZ(420,"code"),e._uU(421,"options"),e.qZA(),e._uU(422," object. ("),e.TgZ(423,"strong"),e._uU(424,"Note"),e.qZA(),e._uU(425,": for the time being, since we "),e.TgZ(426,"em"),e._uU(427,"haven't"),e.qZA(),e._uU(428," actually determined how to pass it in, we'll just hard-code "),e.TgZ(429,"code"),e._uU(430,"options"),e.qZA(),e._uU(431,". We'll fix this in a minute)."),e.qZA(),e.TgZ(432,"pre")(433,"code",11),e._uU(434,"\nimport { Injectable } from '@nestjs/common';\nimport * as dotenv from 'dotenv';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { EnvConfig } from './interfaces';\n\n@Injectable()\nexport class ConfigService {\n private readonly envConfig: EnvConfig;\n\n constructor() {\n const options = { folder: './config' };\n\n const filePath = `${process.env.NODE_ENV || 'development'}.env`;\n const envFile = path.resolve(__dirname, '../../', options.folder, filePath);\n this.envConfig = dotenv.parse(fs.readFileSync(envFile));\n }\n\n get(key: string): string {\n return this.envConfig[key];\n }\n}\n"),e.qZA()(),e.TgZ(435,"p"),e._uU(436,"Now our "),e.TgZ(437,"code"),e._uU(438,"ConfigService"),e.qZA(),e._uU(439," knows how to find the "),e.TgZ(440,"code"),e._uU(441,".env"),e.qZA(),e._uU(442," file in the folder we've specified in "),e.TgZ(443,"code"),e._uU(444,"options"),e.qZA(),e._uU(445,"."),e.qZA(),e.TgZ(446,"p"),e._uU(447,"Our remaining task is to somehow inject the "),e.TgZ(448,"code"),e._uU(449,"options"),e.qZA(),e._uU(450," object from the "),e.TgZ(451,"code"),e._uU(452,"register()"),e.qZA(),e._uU(453," step into our "),e.TgZ(454,"code"),e._uU(455,"ConfigService"),e.qZA(),e._uU(456,". And of course, we'll use "),e.TgZ(457,"em"),e._uU(458,"dependency injection"),e.qZA(),e._uU(459," to do it. This is a key point, so make sure you understand it. Our "),e.TgZ(460,"code"),e._uU(461,"ConfigModule"),e.qZA(),e._uU(462," is providing "),e.TgZ(463,"code"),e._uU(464,"ConfigService"),e.qZA(),e._uU(465,". "),e.TgZ(466,"code"),e._uU(467,"ConfigService"),e.qZA(),e._uU(468," in turn depends on the "),e.TgZ(469,"code"),e._uU(470,"options"),e.qZA(),e._uU(471," object that is only supplied at run-time. So, at run-time, we'll need to first bind the "),e.TgZ(472,"code"),e._uU(473,"options"),e.qZA(),e._uU(474," object to the Nest IoC container, and then have Nest inject it into our "),e.TgZ(475,"code"),e._uU(476,"ConfigService"),e.qZA(),e._uU(477,". Remember from the "),e.TgZ(478,"strong"),e._uU(479,"Custom providers"),e.qZA(),e._uU(480," chapter that providers can "),e.TgZ(481,"a",19),e._uU(482,"include any value"),e.qZA(),e._uU(483," not just services, so we're fine using dependency injection to handle a simple "),e.TgZ(484,"code"),e._uU(485,"options"),e.qZA(),e._uU(486," object."),e.qZA(),e.TgZ(487,"p"),e._uU(488,"Let's tackle binding the options object to the IoC container first. We do this in our static "),e.TgZ(489,"code"),e._uU(490,"register()"),e.qZA(),e._uU(491," method. Remember that we are dynamically constructing a module, and one of the properties of a module is its list of providers. So what we need to do is define our options object as a provider. This will make it injectable into the "),e.TgZ(492,"code"),e._uU(493,"ConfigService"),e.qZA(),e._uU(494,", which we'll take advantage of in the next step. In the code below, pay attention to the "),e.TgZ(495,"code"),e._uU(496,"providers"),e.qZA(),e._uU(497," array:"),e.qZA(),e.TgZ(498,"pre")(499,"code",11),e._uU(500,"\nimport { DynamicModule, Module } from '@nestjs/common';\nimport { ConfigService } from './config.service';\n\n@Module({})\nexport class ConfigModule {\n static register(options: Record<string, any>): DynamicModule {\n return {\n module: ConfigModule,\n providers: [\n {\n provide: 'CONFIG_OPTIONS',\n useValue: options,\n },\n ConfigService,\n ],\n exports: [ConfigService],\n };\n }\n}\n"),e.qZA()(),e.TgZ(501,"p"),e._uU(502,"Now we can complete the process by injecting the "),e.TgZ(503,"code"),e._uU(504,"'CONFIG_OPTIONS'"),e.qZA(),e._uU(505," provider into the "),e.TgZ(506,"code"),e._uU(507,"ConfigService"),e.qZA(),e._uU(508,". Recall that when we define a provider using a non-class token we need to use the "),e.TgZ(509,"code"),e._uU(510,"@Inject()"),e.qZA(),e._uU(511," decorator "),e.TgZ(512,"a",20),e._uU(513,"as described here"),e.qZA(),e._uU(514,"."),e.qZA(),e.TgZ(515,"pre")(516,"code",11),e._uU(517,"\nimport * as dotenv from 'dotenv';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { Injectable, Inject } from '@nestjs/common';\nimport { EnvConfig } from './interfaces';\n\n@Injectable()\nexport class ConfigService {\n private readonly envConfig: EnvConfig;\n\n constructor(@Inject('CONFIG_OPTIONS') private options: Record<string, any>) {\n const filePath = `${process.env.NODE_ENV || 'development'}.env`;\n const envFile = path.resolve(__dirname, '../../', options.folder, filePath);\n this.envConfig = dotenv.parse(fs.readFileSync(envFile));\n }\n\n get(key: string): string {\n return this.envConfig[key];\n }\n}\n"),e.qZA()(),e.TgZ(518,"p"),e._uU(519,"One final note: for simplicity we used a string-based injection token ("),e.TgZ(520,"code"),e._uU(521,"'CONFIG_OPTIONS'"),e.qZA(),e._uU(522,") above, but best practice is to define it as a constant (or "),e.TgZ(523,"code"),e._uU(524,"Symbol"),e.qZA(),e._uU(525,") in a separate file, and import that file. For example:"),e.qZA(),e.TgZ(526,"pre")(527,"code",11),e._uU(528,"\nexport const CONFIG_OPTIONS = 'CONFIG_OPTIONS';\n"),e.qZA()(),e.TgZ(529,"h4",21)(530,"span"),e._uU(531,"Example"),e.qZA()(),e.TgZ(532,"p"),e._uU(533,"A full example of the code in this chapter can be found "),e.TgZ(534,"a",16),e._uU(535,"here"),e.qZA(),e._uU(536,"."),e.qZA(),e.TgZ(537,"h4",22)(538,"span"),e._uU(539,"Community guidelines"),e.qZA()(),e.TgZ(540,"p"),e._uU(541,"You may have seen the use for methods like "),e.TgZ(542,"code"),e._uU(543,"forRoot"),e.qZA(),e._uU(544,", "),e.TgZ(545,"code"),e._uU(546,"register"),e.qZA(),e._uU(547,", and "),e.TgZ(548,"code"),e._uU(549,"forFeature"),e.qZA(),e._uU(550," around some of the "),e.TgZ(551,"code"),e._uU(552,"@nestjs/"),e.qZA(),e._uU(553," packages and may be wondering what the difference for all of these methods are. There is no hard rule about this, but the "),e.TgZ(554,"code"),e._uU(555,"@nestjs/"),e.qZA(),e._uU(556," packages try to follow these guidelines:"),e.qZA(),e.TgZ(557,"p"),e._uU(558,"When creating a module with:"),e.qZA(),e.TgZ(559,"ul")(560,"li")(561,"p")(562,"code"),e._uU(563,"register"),e.qZA(),e._uU(564,", you are expecting to configure a dynamic module with a specific configuration for use only by the calling module. For example, with Nest's "),e.TgZ(565,"code"),e._uU(566,"@nestjs/axios"),e.qZA(),e._uU(567,": "),e.TgZ(568,"code"),e._uU(569),e.qZA(),e._uU(570,". If, in another module you use "),e.TgZ(571,"code"),e._uU(572),e.qZA(),e._uU(573,", it will have the different configuration. You can do this for as many modules as you want."),e.qZA()(),e.TgZ(574,"li")(575,"p")(576,"code"),e._uU(577,"forRoot"),e.qZA(),e._uU(578,", you are expecting to configure a dynamic module once and reuse that configuration in multiple places (though possibly unknowingly as it's abstracted away). This is why you have one "),e.TgZ(579,"code"),e._uU(580,"GraphQLModule.forRoot()"),e.qZA(),e._uU(581,", one "),e.TgZ(582,"code"),e._uU(583,"TypeOrmModule.forRoot()"),e.qZA(),e._uU(584,", etc."),e.qZA()(),e.TgZ(585,"li")(586,"p")(587,"code"),e._uU(588,"forFeature"),e.qZA(),e._uU(589,", you are expecting to use the configuration of a dynamic module's "),e.TgZ(590,"code"),e._uU(591,"forRoot"),e.qZA(),e._uU(592," but need to modify some configuration specific to the calling module's needs (i.e. which repository this module should have access to, or the context that a logger should use.)"),e.qZA()()(),e.TgZ(593,"p"),e._uU(594,"All of these, usually, have their "),e.TgZ(595,"code"),e._uU(596,"async"),e.qZA(),e._uU(597," counterparts as well, "),e.TgZ(598,"code"),e._uU(599,"registerAsync"),e.qZA(),e._uU(600,", "),e.TgZ(601,"code"),e._uU(602,"forRootAsync"),e.qZA(),e._uU(603,", and "),e.TgZ(604,"code"),e._uU(605,"forFeatureAsync"),e.qZA(),e._uU(606,", that mean the same thing, but use Nest's Dependency Injection for the configuration as well."),e.qZA(),e.TgZ(607,"h4",23)(608,"span"),e._uU(609,"Configurable module builder"),e.qZA()(),e.TgZ(610,"p"),e._uU(611,"As manually creating highly configurable, dynamic modules that expose "),e.TgZ(612,"code"),e._uU(613,"async"),e.qZA(),e._uU(614," methods ("),e.TgZ(615,"code"),e._uU(616,"registerAsync"),e.qZA(),e._uU(617,", "),e.TgZ(618,"code"),e._uU(619,"forRootAsync"),e.qZA(),e._uU(620,", etc.) is quite complicated, especially for newcomers, Nest exposes the "),e.TgZ(621,"code"),e._uU(622,"ConfigurableModuleBuilder"),e.qZA(),e._uU(623,' class that facilitates this process and lets you construct a module "blueprint" in just a few lines of code.'),e.qZA(),e.TgZ(624,"p"),e._uU(625,"For example, let's take the example we used above ("),e.TgZ(626,"code"),e._uU(627,"ConfigModule"),e.qZA(),e._uU(628,") and convert it to use the "),e.TgZ(629,"code"),e._uU(630,"ConfigurableModuleBuilder"),e.qZA(),e._uU(631,". Before we start, let's make sure we create a dedicated interface that represents what options our "),e.TgZ(632,"code"),e._uU(633,"ConfigModule"),e.qZA(),e._uU(634," takes in."),e.qZA(),e.TgZ(635,"pre")(636,"code",11),e._uU(637,"\nexport interface ConfigModuleOptions {\n folder: string;\n}\n"),e.qZA()(),e.TgZ(638,"p"),e._uU(639,"With this in place, create a new dedicated file (alongside the existing "),e.TgZ(640,"code"),e._uU(641,"config.module.ts"),e.qZA(),e._uU(642," file) and name it "),e.TgZ(643,"code"),e._uU(644,"config.module-definition.ts"),e.qZA(),e._uU(645,". In this file, let's utilize the "),e.TgZ(646,"code"),e._uU(647,"ConfigurableModuleBuilder"),e.qZA(),e._uU(648," to construct "),e.TgZ(649,"code"),e._uU(650,"ConfigModule"),e.qZA(),e._uU(651," definition."),e.qZA(),e.TgZ(652,"span",24),e._uU(653),e.ALo(654,"extension"),e._UZ(655,"app-tabs",null,25),e.qZA(),e.TgZ(657,"pre")(658,"code",11),e._uU(659,"\nimport { ConfigurableModuleBuilder } from '@nestjs/common';\nimport { ConfigModuleOptions } from './interfaces/config-module-options.interface';\n\nexport const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN } =\n new ConfigurableModuleBuilder<ConfigModuleOptions>().build();\n"),e.qZA()(),e.TgZ(660,"pre")(661,"code",11),e._uU(662,"\nimport { ConfigurableModuleBuilder } from '@nestjs/common';\n\nexport const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN } =\n new ConfigurableModuleBuilder().build();\n"),e.qZA()(),e.TgZ(663,"p"),e._uU(664,"Now let's open up the "),e.TgZ(665,"code"),e._uU(666,"config.module.ts"),e.qZA(),e._uU(667," file and modify its implementation to leverage the auto-generated "),e.TgZ(668,"code"),e._uU(669,"ConfigurableModuleClass"),e.qZA(),e._uU(670,":"),e.qZA(),e.TgZ(671,"pre")(672,"code",11),e._uU(673,"\nimport { Module } from '@nestjs/common';\nimport { ConfigService } from './config.service';\nimport { ConfigurableModuleClass } from './config.module-definition';\n\n@Module({\n providers: [ConfigService],\n exports: [ConfigService],\n})\nexport class ConfigModule extends ConfigurableModuleClass {}\n"),e.qZA()(),e.TgZ(674,"p"),e._uU(675,"Extending the "),e.TgZ(676,"code"),e._uU(677,"ConfigurableModuleClass"),e.qZA(),e._uU(678," means that "),e.TgZ(679,"code"),e._uU(680,"ConfigModule"),e.qZA(),e._uU(681," provides now not only the "),e.TgZ(682,"code"),e._uU(683,"register"),e.qZA(),e._uU(684," method (as previously with the custom implementation), but also the "),e.TgZ(685,"code"),e._uU(686,"registerAsync"),e.qZA(),e._uU(687," method which allows consumers asynchronously configure that module, for example, by supplying async factories:"),e.qZA(),e.TgZ(688,"pre")(689,"code",11),e._uU(690,"\n@Module({\n imports: [\n ConfigModule.register({ folder: './config' }),\n // or alternatively:\n // ConfigModule.registerAsync({\n // useFactory: () => {\n // return {\n // folder: './config',\n // }\n // },\n // inject: [...any extra dependencies...]\n // }),\n ],\n})\nexport class AppModule {}\n"),e.qZA()(),e.TgZ(691,"p"),e._uU(692,"Lastly, let's update the "),e.TgZ(693,"code"),e._uU(694,"ConfigService"),e.qZA(),e._uU(695," class to inject the generated module options' provider instead of the "),e.TgZ(696,"code"),e._uU(697,"'CONFIG_OPTIONS'"),e.qZA(),e._uU(698," that we used so far."),e.qZA(),e.TgZ(699,"pre")(700,"code",11),e._uU(701,"\n@Injectable()\nexport class ConfigService {\n constructor(@Inject(MODULE_OPTIONS_TOKEN) private options: ConfigModuleOptions) { ... }\n}\n"),e.qZA()(),e.TgZ(702,"h4",26)(703,"span"),e._uU(704,"Custom method key"),e.qZA()(),e.TgZ(705,"p")(706,"code"),e._uU(707,"ConfigurableModuleClass"),e.qZA(),e._uU(708," by default provides the "),e.TgZ(709,"code"),e._uU(710,"register"),e.qZA(),e._uU(711," and its counterpart "),e.TgZ(712,"code"),e._uU(713,"registerAsync"),e.qZA(),e._uU(714," methods. To use a different method name, use the "),e.TgZ(715,"code"),e._uU(716,"ConfigurableModuleBuilder#setClassMethodName"),e.qZA(),e._uU(717," method, as follows:"),e.qZA(),e.TgZ(718,"span",24),e._uU(719),e.ALo(720,"extension"),e._UZ(721,"app-tabs",null,27),e.qZA(),e.TgZ(723,"pre")(724,"code",11),e._uU(725,"\nexport const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN } =\n new ConfigurableModuleBuilder<ConfigModuleOptions>().setClassMethodName('forRoot').build();\n"),e.qZA()(),e.TgZ(726,"pre")(727,"code",11),e._uU(728,"\nexport const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN } =\n new ConfigurableModuleBuilder().setClassMethodName('forRoot').build();\n"),e.qZA()(),e.TgZ(729,"p"),e._uU(730,"This construction will instruct "),e.TgZ(731,"code"),e._uU(732,"ConfigurableModuleBuilder"),e.qZA(),e._uU(733," to generate a class that exposes "),e.TgZ(734,"code"),e._uU(735,"forRoot"),e.qZA(),e._uU(736," and "),e.TgZ(737,"code"),e._uU(738,"forRootAsync"),e.qZA(),e._uU(739," instead. Example:"),e.qZA(),e.TgZ(740,"pre")(741,"code",11),e._uU(742,"\n@Module({\n imports: [\n ConfigModule.forRoot({ folder: './config' }), // <-- note the use of \"forRoot\" instead of \"register\"\n // or alternatively:\n // ConfigModule.forRootAsync({\n // useFactory: () => {\n // return {\n // folder: './config',\n // }\n // },\n // inject: [...any extra dependencies...]\n // }),\n ],\n})\nexport class AppModule {}\n"),e.qZA()(),e.TgZ(743,"h4",28)(744,"span"),e._uU(745,"Custom options factory class"),e.qZA()(),e.TgZ(746,"p"),e._uU(747,"Since the "),e.TgZ(748,"code"),e._uU(749,"registerAsync"),e.qZA(),e._uU(750," method (or "),e.TgZ(751,"code"),e._uU(752,"forRootAsync"),e.qZA(),e._uU(753," or any other name, depending on the configuration) lets consumer pass a provider definition that resolves to the module configuration, a library consumer could potentially supply a class to be used to construct the configuration object."),e.qZA(),e.TgZ(754,"pre")(755,"code",11),e._uU(756,"\n@Module({\n imports: [\n ConfigModule.registerAsync({\n useClass: ConfigModuleOptionsFactory,\n }),\n ],\n})\nexport class AppModule {}\n"),e.qZA()(),e.TgZ(757,"p"),e._uU(758,"This class, by default, must provide the "),e.TgZ(759,"code"),e._uU(760,"create()"),e.qZA(),e._uU(761," method that returns a module configuration object. However, if your library follows a different naming convention, you can change that behavior and instruct "),e.TgZ(762,"code"),e._uU(763,"ConfigurableModuleBuilder"),e.qZA(),e._uU(764," to expect a different method, for example, "),e.TgZ(765,"code"),e._uU(766,"createConfigOptions"),e.qZA(),e._uU(767,", using the "),e.TgZ(768,"code"),e._uU(769,"ConfigurableModuleBuilder#setFactoryMethodName"),e.qZA(),e._uU(770," method:"),e.qZA(),e.TgZ(771,"span",24),e._uU(772),e.ALo(773,"extension"),e._UZ(774,"app-tabs",null,29),e.qZA(),e.TgZ(776,"pre")(777,"code",11),e._uU(778,"\nexport const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN } =\n new ConfigurableModuleBuilder<ConfigModuleOptions>().setFactoryMethodName('createConfigOptions').build();\n"),e.qZA()(),e.TgZ(779,"pre")(780,"code",11),e._uU(781,"\nexport const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN } =\n new ConfigurableModuleBuilder().setFactoryMethodName('createConfigOptions').build();\n"),e.qZA()(),e.TgZ(782,"p"),e._uU(783,"Now, "),e.TgZ(784,"code"),e._uU(785,"ConfigModuleOptionsFactory"),e.qZA(),e._uU(786," class must expose the "),e.TgZ(787,"code"),e._uU(788,"createConfigOptions"),e.qZA(),e._uU(789," method (instead of "),e.TgZ(790,"code"),e._uU(791,"create"),e.qZA(),e._uU(792,"):"),e.qZA(),e.TgZ(793,"pre")(794,"code",11),e._uU(795,'\n@Module({\n imports: [\n ConfigModule.registerAsync({\n useClass: ConfigModuleOptionsFactory, // <-- this class must provide the "createConfigOptions" method\n }),\n ],\n})\nexport class AppModule {}\n'),e.qZA()(),e.TgZ(796,"h4",30)(797,"span"),e._uU(798,"Extra options"),e.qZA()(),e.TgZ(799,"p"),e._uU(800,"There are edge-cases when your module may need to take extra options that determine how it is supposed to behave (a nice example of such an option is the "),e.TgZ(801,"code"),e._uU(802,"isGlobal"),e.qZA(),e._uU(803," flag - or just "),e.TgZ(804,"code"),e._uU(805,"global"),e.qZA(),e._uU(806,") that at the same time, shouldn't be included in the "),e.TgZ(807,"code"),e._uU(808,"MODULE_OPTIONS_TOKEN"),e.qZA(),e._uU(809," provider (as they are irrelevant to services/providers registered within that module, for example, "),e.TgZ(810,"code"),e._uU(811,"ConfigService"),e.qZA(),e._uU(812," does not need to know whether its host module is registered as a global module)."),e.qZA(),e.TgZ(813,"p"),e._uU(814,"In such cases, the "),e.TgZ(815,"code"),e._uU(816,"ConfigurableModuleBuilder#setExtras"),e.qZA(),e._uU(817," method can be used. See the following example:"),e.qZA(),e.TgZ(818,"pre")(819,"code",11),e._uU(820,"\nexport const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN } = new ConfigurableModuleBuilder<ConfigModuleOptions>()\n .setExtras(\n {\n isGlobal: true,\n },\n (definition, extras) => ({\n ...definition,\n global: extras.isGlobal,\n }),\n )\n .build();\n"),e.qZA()(),e.TgZ(821,"p"),e._uU(822,"In the example above, the first argument passed into the "),e.TgZ(823,"code"),e._uU(824,"setExtras"),e.qZA(),e._uU(825,' method is an object containing default values for the "extra" properties. The second argument is a function that takes an auto-generated module definitions (with '),e.TgZ(826,"code"),e._uU(827,"provider"),e.qZA(),e._uU(828,", "),e.TgZ(829,"code"),e._uU(830,"exports"),e.qZA(),e._uU(831,", etc.) and "),e.TgZ(832,"code"),e._uU(833,"extras"),e.qZA(),e._uU(834," object which represents extra properties (either specified by the consumer or defaults). The returned value of this function is a modified module definition. In this specific example, we're taking the "),e.TgZ(835,"code"),e._uU(836,"extras.isGlobal"),e.qZA(),e._uU(837," property and assigning it to the "),e.TgZ(838,"code"),e._uU(839,"global"),e.qZA(),e._uU(840," property of the module definition (which in turn determines whether a module is global or not, read more "),e.TgZ(841,"a",31),e._uU(842,"here"),e.qZA(),e._uU(843,")."),e.qZA(),e.TgZ(844,"p"),e._uU(845,"Now when consuming this module, the additional "),e.TgZ(846,"code"),e._uU(847,"isGlobal"),e.qZA(),e._uU(848," flag can be passed in, as follows:"),e.qZA(),e.TgZ(849,"pre")(850,"code",11),e._uU(851,"\n@Module({\n imports: [\n ConfigModule.register({\n isGlobal: true,\n folder: './config',\n }),\n ],\n})\nexport class AppModule {}\n"),e.qZA()(),e.TgZ(852,"p"),e._uU(853,"However, since "),e.TgZ(854,"code"),e._uU(855,"isGlobal"),e.qZA(),e._uU(856,' is declared as an "extra" property, it won\'t be available in the '),e.TgZ(857,"code"),e._uU(858,"MODULE_OPTIONS_TOKEN"),e.qZA(),e._uU(859," provider:"),e.qZA(),e.TgZ(860,"pre")(861,"code",11),e._uU(862,'\n@Injectable()\nexport class ConfigService {\n constructor(@Inject(MODULE_OPTIONS_TOKEN) private options: ConfigModuleOptions) {\n // "options" object will not have the "isGlobal" property\n // ...\n }\n}\n'),e.qZA()(),e.TgZ(863,"h4",32)(864,"span"),e._uU(865,"Extending auto-generated methods"),e.qZA()(),e.TgZ(866,"p"),e._uU(867,"The auto-generated static methods ("),e.TgZ(868,"code"),e._uU(869,"register"),e.qZA(),e._uU(870,", "),e.TgZ(871,"code"),e._uU(872,"registerAsync"),e.qZA(),e._uU(873,", etc.) can be extended if needed, as follows:"),e.qZA(),e.TgZ(874,"pre")(875,"code",11),e._uU(876,"\nimport { Module } from '@nestjs/common';\nimport { ConfigService } from './config.service';\nimport { ConfigurableModuleClass, ASYNC_OPTIONS_TYPE, OPTIONS_TYPE } from './config.module-definition';\n\n@Module({\n providers: [ConfigService],\n exports: [ConfigService],\n})\nexport class ConfigModule extends ConfigurableModuleClass {\n static register(options: typeof OPTIONS_TYPE): DynamicModule {\n return {\n // your custom logic here\n ...super.register(options),\n };\n }\n\n static registerAsync(options: typeof ASYNC_OPTIONS_TYPE): DynamicModule {\n return {\n // your custom logic here\n ...super.registerAsync(options),\n };\n }\n}\n"),e.qZA()(),e.TgZ(877,"p"),e._uU(878,"Note the use of "),e.TgZ(879,"code"),e._uU(880,"OPTIONS_TYPE"),e.qZA(),e._uU(881," and "),e.TgZ(882,"code"),e._uU(883,"ASYNC_OPTIONS_TYPE"),e.qZA(),e._uU(884," types that must be exported from the module definition file:"),e.qZA(),e.TgZ(885,"pre")(886,"code",11),e._uU(887,"\nexport const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN, OPTIONS_TYPE, ASYNC_OPTIONS_TYPE } = new ConfigurableModuleBuilder<ConfigModuleOptions>().build();\n"),e.qZA()()()),2&n){const a=e.MAs(656),r=e.MAs(722),i=e.MAs(775);e.xp6(569),e.AsE("HttpModule.register(","{"," baseUrl: 'someUrl' ","}",")"),e.xp6(3),e.AsE("HttpModule.register(","{"," baseUrl: 'somewhere else' ","}",")"),e.xp6(81),e.hij(" ",e.xi3(654,19,"config.module-definition",a.isJsActive),"\n"),e.xp6(4),e.ekj("hide",a.isJsActive),e.xp6(3),e.ekj("hide",!a.isJsActive),e.xp6(59),e.hij(" ",e.xi3(720,22,"config.module-definition",r.isJsActive),"\n"),e.xp6(4),e.ekj("hide",r.isJsActive),e.xp6(3),e.ekj("hide",!r.isJsActive),e.xp6(46),e.hij(" ",e.xi3(773,25,"config.module-definition",i.isJsActive),"\n"),e.xp6(4),e.ekj("hide",i.isJsActive),e.xp6(3),e.ekj("hide",!i.isJsActive)}},dependencies:[h.n,l.U,v.E,p.rH,U.F],encapsulation:2,changeDetection:0})}return t})(),j=(()=>{class t extends d.y{static \u0275fac=function(){let o;return function(s){return(o||(o=e.n5z(t)))(s||t)}}();static \u0275cmp=e.Xpm({type:t,selectors:[["app-lifecycle-events"]],features:[e.qOj],decls:297,vars:12,consts:[[1,"content"],["contentReference",""],[1,"github-links"],["href","https://github.com/ChuTingzj/docs.nestjs.zh-cn.com/tree/master/content/fundamentals/lifecycle-events.md","aria-label","Suggest Edits","title","Suggest Edits"],[1,"fas","fa-edit"],["id","lifecycle-events"],["appAnchor","","id","lifecycle-sequence"],["src","/assets/lifecycle-events.png"],["appAnchor","","id","lifecycle-events-1"],["rel","nofollow","target","_blank","href","https://docs.nestjs.com/fundamentals/lifecycle-events#application-shutdown"],["href","fundamentals/lifecycle-events#application-shutdown"],[1,"warning"],[1,"info"],["appAnchor","","id","usage"],[1,"filename"],["appa17ba512dc4d61973e916930e2d719a218512f08",""],[1,"language-typescript"],["appAnchor","","id","asynchronous-initialization"],["appb0325f6084977b581bde1972751ba1c3d30d0325",""],["appAnchor","","id","application-shutdown"],["rel","nofollow","target","_blank","href","https://kubernetes.io/"],["rel","nofollow","target","_blank","href","https://www.heroku.com/"],["rel","nofollow","target","_blank","href","https://nodejs.org/api/process.html#process_signal_events"],["rel","nofollow","target","_blank","href","https://docs.libuv.org/en/v1.x/signal.html"],["app58a364a92650a79095f0cb74db2c4f6a8572d435",""]],template:function(n,s){if(1&n&&(e.TgZ(0,"div",0,1)(2,"div",2)(3,"a",3),e._UZ(4,"i",4),e.qZA()(),e.TgZ(5,"h3",5),e._uU(6,"Lifecycle Events"),e.qZA(),e.TgZ(7,"p"),e._uU(8,"A Nest application, as well as every application element, has a lifecycle managed by Nest. Nest provides "),e.TgZ(9,"strong"),e._uU(10,"lifecycle hooks"),e.qZA(),e._uU(11," that give visibility into key lifecycle events, and the ability to act (run registered code on your modules, providers or controllers) when they occur."),e.qZA(),e.TgZ(12,"h4",6)(13,"span"),e._uU(14,"Lifecycle sequence"),e.qZA()(),e.TgZ(15,"p"),e._uU(16,"The following diagram depicts the sequence of key application lifecycle events, from the time the application is bootstrapped until the node process exits. We can divide the overall lifecycle into three phases: "),e.TgZ(17,"strong"),e._uU(18,"initializing"),e.qZA(),e._uU(19,", "),e.TgZ(20,"strong"),e._uU(21,"running"),e.qZA(),e._uU(22," and "),e.TgZ(23,"strong"),e._uU(24,"terminating"),e.qZA(),e._uU(25,". Using this lifecycle, you can plan for appropriate initialization of modules and services, manage active connections, and gracefully shutdown your application when it receives a termination signal."),e.qZA(),e.TgZ(26,"figure"),e._UZ(27,"img",7),e.qZA(),e.TgZ(28,"h4",8)(29,"span"),e._uU(30,"Lifecycle events"),e.qZA()(),e.TgZ(31,"p"),e._uU(32,"Lifecycle events happen during application bootstrapping and shutdown. Nest calls registered lifecycle hook methods on modules, providers and controllers at each of the following lifecycle events ("),e.TgZ(33,"strong"),e._uU(34,"shutdown hooks"),e.qZA(),e._uU(35," need to be enabled first, as described "),e.TgZ(36,"a",9),e._uU(37,"below"),e.qZA(),e._uU(38,"). As shown in the diagram above, Nest also calls the appropriate underlying methods to begin listening for connections, and to stop listening for connections."),e.qZA(),e.TgZ(39,"p"),e._uU(40,"In the following table, "),e.TgZ(41,"code"),e._uU(42,"onModuleDestroy"),e.qZA(),e._uU(43,", "),e.TgZ(44,"code"),e._uU(45,"beforeApplicationShutdown"),e.qZA(),e._uU(46," and "),e.TgZ(47,"code"),e._uU(48,"onApplicationShutdown"),e.qZA(),e._uU(49," are only triggered if you explicitly call "),e.TgZ(50,"code"),e._uU(51,"app.close()"),e.qZA(),e._uU(52," or if the process receives a special system signal (such as SIGTERM) and you have correctly called "),e.TgZ(53,"code"),e._uU(54,"enableShutdownHooks"),e.qZA(),e._uU(55," at application bootstrap (see below "),e.TgZ(56,"strong"),e._uU(57,"Application shutdown"),e.qZA(),e._uU(58," part)."),e.qZA(),e.TgZ(59,"table")(60,"thead")(61,"tr")(62,"th"),e._uU(63,"Lifecycle hook method"),e.qZA(),e.TgZ(64,"th"),e._uU(65,"Lifecycle event triggering the hook method call"),e.qZA()()(),e.TgZ(66,"tbody")(67,"tr")(68,"td")(69,"code"),e._uU(70,"onModuleInit()"),e.qZA()(),e.TgZ(71,"td"),e._uU(72,"Called once the host module's dependencies have been resolved."),e.qZA()(),e.TgZ(73,"tr")(74,"td")(75,"code"),e._uU(76,"onApplicationBootstrap()"),e.qZA()(),e.TgZ(77,"td"),e._uU(78,"Called once all modules have been initialized, but before listening for connections."),e.qZA()(),e.TgZ(79,"tr")(80,"td")(81,"code"),e._uU(82,"onModuleDestroy()"),e.qZA(),e._uU(83,"*"),e.qZA(),e.TgZ(84,"td"),e._uU(85,"Called after a termination signal (e.g., "),e.TgZ(86,"code"),e._uU(87,"SIGTERM"),e.qZA(),e._uU(88,") has been received."),e.qZA()(),e.TgZ(89,"tr")(90,"td")(91,"code"),e._uU(92,"beforeApplicationShutdown()"),e.qZA(),e._uU(93,"*"),e.qZA(),e.TgZ(94,"td"),e._uU(95,"Called after all "),e.TgZ(96,"code"),e._uU(97,"onModuleDestroy()"),e.qZA(),e._uU(98," handlers have completed (Promises resolved or rejected);"),e._UZ(99,"br"),e._uU(100,"once complete (Promises resolved or rejected), all existing connections will be closed ("),e.TgZ(101,"code"),e._uU(102,"app.close()"),e.qZA(),e._uU(103," called)."),e.qZA()(),e.TgZ(104,"tr")(105,"td")(106,"code"),e._uU(107,"onApplicationShutdown()"),e.qZA(),e._uU(108,"*"),e.qZA(),e.TgZ(109,"td"),e._uU(110,"Called after connections close ("),e.TgZ(111,"code"),e._uU(112,"app.close()"),e.qZA(),e._uU(113," resolves)."),e.qZA()()()(),e.TgZ(114,"p"),e._uU(115,"* For these events, if you're not calling "),e.TgZ(116,"code"),e._uU(117,"app.close()"),e.qZA(),e._uU(118," explicitly, you must opt-in to make them work with system signals such as "),e.TgZ(119,"code"),e._uU(120,"SIGTERM"),e.qZA(),e._uU(121,". See "),e.TgZ(122,"a",10),e._uU(123,"Application shutdown"),e.qZA(),e._uU(124," below."),e.qZA(),e.TgZ(125,"blockquote",11)(126,"strong"),e._uU(127,"Warning"),e.qZA(),e._uU(128," The lifecycle hooks listed above are not triggered for "),e.TgZ(129,"strong"),e._uU(130,"request-scoped"),e.qZA(),e._uU(131," classes. Request-scoped classes are not tied to the application lifecycle and their lifespan is unpredictable. They are exclusively created for each request and automatically garbage-collected after the response is sent.\n"),e.qZA(),e.TgZ(132,"blockquote",12)(133,"strong"),e._uU(134,"Hint"),e.qZA(),e._uU(135," Execution order of "),e.TgZ(136,"code"),e._uU(137,"onModuleInit()"),e.qZA(),e._uU(138," and "),e.TgZ(139,"code"),e._uU(140,"onApplicationBootstrap()"),e.qZA(),e._uU(141," directly depends on the order of module imports, awaiting the previous hook.\n"),e.qZA(),e.TgZ(142,"h4",13)(143,"span"),e._uU(144,"Usage"),e.qZA()(),e.TgZ(145,"p"),e._uU(146,"Each lifecycle hook is represented by an interface. Interfaces are technically optional because they do not exist after TypeScript compilation. Nonetheless, it's good practice to use them in order to benefit from strong typing and editor tooling. To register a lifecycle hook, implement the appropriate interface. For example, to register a method to be called during module initialization on a particular class (e.g., Controller, Provider or Module), implement the "),e.TgZ(147,"code"),e._uU(148,"OnModuleInit"),e.qZA(),e._uU(149," interface by supplying an "),e.TgZ(150,"code"),e._uU(151,"onModuleInit()"),e.qZA(),e._uU(152," method, as shown below:"),e.qZA(),e.TgZ(153,"span",14),e._UZ(154,"app-tabs",null,15),e.qZA(),e.TgZ(156,"pre")(157,"code",16),e._uU(158,"\nimport { Injectable, OnModuleInit } from '@nestjs/common';\n\n@Injectable()\nexport class UsersService implements OnModuleInit {\n onModuleInit() {\n console.log(`The module has been initialized.`);\n }\n}\n"),e.qZA()(),e.TgZ(159,"pre")(160,"code",16),e._uU(161,"\nimport { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class UsersService {\n onModuleInit() {\n console.log(`The module has been initialized.`);\n }\n}\n"),e.qZA()(),e.TgZ(162,"h4",17)(163,"span"),e._uU(164,"Asynchronous initialization"),e.qZA()(),e.TgZ(165,"p"),e._uU(166,"Both the "),e.TgZ(167,"code"),e._uU(168,"OnModuleInit"),e.qZA(),e._uU(169," and "),e.TgZ(170,"code"),e._uU(171,"OnApplicationBootstrap"),e.qZA(),e._uU(172," hooks allow you to defer the application initialization process (return a "),e.TgZ(173,"code"),e._uU(174,"Promise"),e.qZA(),e._uU(175," or mark the method as "),e.TgZ(176,"code"),e._uU(177,"async"),e.qZA(),e._uU(178," and "),e.TgZ(179,"code"),e._uU(180,"await"),e.qZA(),e._uU(181," an asynchronous method completion in the method body)."),e.qZA(),e.TgZ(182,"span",14),e._UZ(183,"app-tabs",null,18),e.qZA(),e.TgZ(185,"pre")(186,"code",16),e._uU(187,"\nasync onModuleInit(): Promise<void> {\n await this.fetch();\n}\n"),e.qZA()(),e.TgZ(188,"pre")(189,"code",16),e._uU(190,"\nasync onModuleInit() {\n await this.fetch();\n}\n"),e.qZA()(),e.TgZ(191,"h4",19)(192,"span"),e._uU(193,"Application shutdown"),e.qZA()(),e.TgZ(194,"p"),e._uU(195,"The "),e.TgZ(196,"code"),e._uU(197,"onModuleDestroy()"),e.qZA(),e._uU(198,", "),e.TgZ(199,"code"),e._uU(200,"beforeApplicationShutdown()"),e.qZA(),e._uU(201," and "),e.TgZ(202,"code"),e._uU(203,"onApplicationShutdown()"),e.qZA(),e._uU(204," hooks are called in the terminating phase (in response to an explicit call to "),e.TgZ(205,"code"),e._uU(206,"app.close()"),e.qZA(),e._uU(207," or upon receipt of system signals such as SIGTERM if opted-in). This feature is often used with "),e.TgZ(208,"a",20),e._uU(209,"Kubernetes"),e.qZA(),e._uU(210," to manage containers' lifecycles, by "),e.TgZ(211,"a",21),e._uU(212,"Heroku"),e.qZA(),e._uU(213," for dynos or similar services."),e.qZA(),e.TgZ(214,"p"),e._uU(215,"Shutdown hook listeners consume system resources, so they are disabled by default. To use shutdown hooks, you "),e.TgZ(216,"strong"),e._uU(217,"must enable listeners"),e.qZA(),e._uU(218," by calling "),e.TgZ(219,"code"),e._uU(220,"enableShutdownHooks()"),e.qZA(),e._uU(221,":"),e.qZA(),e.TgZ(222,"pre")(223,"code",16),e._uU(224,"\nimport { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\n\nasync function bootstrap() {\n const app = await NestFactory.create(AppModule);\n\n // Starts listening for shutdown hooks\n app.enableShutdownHooks();\n\n await app.listen(3000);\n}\nbootstrap();\n"),e.qZA()(),e.TgZ(225,"blockquote",11)(226,"strong"),e._uU(227,"warning"),e.qZA(),e._uU(228," Due to inherent platform limitations, NestJS has limited support for application shutdown hooks on Windows. You can expect "),e.TgZ(229,"code"),e._uU(230,"SIGINT"),e.qZA(),e._uU(231," to work, as well as "),e.TgZ(232,"code"),e._uU(233,"SIGBREAK"),e.qZA(),e._uU(234," and to some extent "),e.TgZ(235,"code"),e._uU(236,"SIGHUP"),e.qZA(),e._uU(237," - "),e.TgZ(238,"a",22),e._uU(239,"read more"),e.qZA(),e._uU(240,". However "),e.TgZ(241,"code"),e._uU(242,"SIGTERM"),e.qZA(),e._uU(243," will never work on Windows because killing a process in the task manager is unconditional, \"i.e., there's no way for an application to detect or prevent it\". Here's some "),e.TgZ(244,"a",23),e._uU(245,"relevant documentation"),e.qZA(),e._uU(246," from libuv to learn more about how "),e.TgZ(247,"code"),e._uU(248,"SIGINT"),e.qZA(),e._uU(249,", "),e.TgZ(250,"code"),e._uU(251,"SIGBREAK"),e.qZA(),e._uU(252," and others are handled on Windows. Also, see Node.js documentation of "),e.TgZ(253,"a",22),e._uU(254,"Process Signal Events"),e.qZA()(),e.TgZ(255,"blockquote",12)(256,"strong"),e._uU(257,"Info"),e.qZA(),e.TgZ(258,"code"),e._uU(259,"enableShutdownHooks"),e.qZA(),e._uU(260," consumes memory by starting listeners. In cases where you are running multiple Nest apps in a single Node process (e.g., when running parallel tests with Jest), Node may complain about excessive listener processes. For this reason, "),e.TgZ(261,"code"),e._uU(262,"enableShutdownHooks"),e.qZA(),e._uU(263," is not enabled by default. Be aware of this condition when you are running multiple instances in a single Node process.\n"),e.qZA(),e.TgZ(264,"p"),e._uU(265,"When the application receives a termination signal it will call any registered "),e.TgZ(266,"code"),e._uU(267,"onModuleDestroy()"),e.qZA(),e._uU(268,", "),e.TgZ(269,"code"),e._uU(270,"beforeApplicationShutdown()"),e.qZA(),e._uU(271,", then "),e.TgZ(272,"code"),e._uU(273,"onApplicationShutdown()"),e.qZA(),e._uU(274," methods (in the sequence described above) with the corresponding signal as the first parameter. If a registered function awaits an asynchronous call (returns a promise), Nest will not continue in the sequence until the promise is resolved or rejected."),e.qZA(),e.TgZ(275,"span",14),e._UZ(276,"app-tabs",null,24),e.qZA(),e.TgZ(278,"pre")(279,"code",16),e._uU(280,'\n@Injectable()\nclass UsersService implements OnApplicationShutdown {\n onApplicationShutdown(signal: string) {\n console.log(signal); // e.g. "SIGINT"\n }\n}\n'),e.qZA()(),e.TgZ(281,"pre")(282,"code",16),e._uU(283,'\n@Injectable()\nclass UsersService implements OnApplicationShutdown {\n onApplicationShutdown(signal) {\n console.log(signal); // e.g. "SIGINT"\n }\n}\n'),e.qZA()(),e.TgZ(284,"blockquote",12)(285,"strong"),e._uU(286,"Info"),e.qZA(),e._uU(287," Calling "),e.TgZ(288,"code"),e._uU(289,"app.close()"),e.qZA(),e._uU(290," doesn't terminate the Node process but only triggers the "),e.TgZ(291,"code"),e._uU(292,"onModuleDestroy()"),e.qZA(),e._uU(293," and "),e.TgZ(294,"code"),e._uU(295,"onApplicationShutdown()"),e.qZA(),e._uU(296," hooks, so if there are some intervals, long-running background tasks, etc. the process won't be automatically terminated.\n"),e.qZA()()),2&n){const a=e.MAs(155),r=e.MAs(184),i=e.MAs(277);e.xp6(156),e.ekj("hide",a.isJsActive),e.xp6(3),e.ekj("hide",!a.isJsActive),e.xp6(26),e.ekj("hide",r.isJsActive),e.xp6(3),e.ekj("hide",!r.isJsActive),e.xp6(90),e.ekj("hide",i.isJsActive),e.xp6(3),e.ekj("hide",!i.isJsActive)}},dependencies:[h.n,l.U],encapsulation:2,changeDetection:0})}return t})(),S=(()=>{class t extends d.y{static \u0275fac=function(){let o;return function(s){return(o||(o=e.n5z(t)))(s||t)}}();static \u0275cmp=e.Xpm({type:t,selectors:[["app-module-ref"]],features:[e.qOj],decls:276,vars:58,consts:[[1,"content"],["contentReference",""],[1,"github-links"],["href","https://github.com/ChuTingzj/docs.nestjs.zh-cn.com/tree/master/content/fundamentals/module-reference.md","aria-label","Suggest Edits","title","Suggest Edits"],[1,"fas","fa-edit"],["id","module-reference"],[1,"filename"],["app33e52ea549aa9265eb2f13028b1822def105cc83",""],[1,"language-typescript"],[1,"info"],["appAnchor","","id","retrieving-instances"],["app27195327928dff75818eff8f2b817f15b9db7cb3",""],[1,"warning"],["href","https://docs.nestjs.com/fundamentals/module-ref#resolving-scoped-providers"],["routerLink","/fundamentals/injection-scopes"],["appAnchor","","id","resolving-scoped-providers"],["appe0e3bb124dbaf14c3e19091e1e608cc8b545fa9a",""],["appc6d88278e3bfb1b72000d6361e797f7c2f052022",""],["app75df8da74e8a41cd41a57f1f03ba0f8caa5632aa",""],["appAnchor","","id","registering-request-provider"],["appAnchor","","id","getting-current-sub-tree"],["app36261c7b161082ba2d60ade64f49be976581f62d",""],["rel","nofollow","target","_blank","href","https://docs.nestjs.com/fundamentals/injection-scopes#request-provider"],["appAnchor","","id","instantiating-custom-classes-dynamically"],["appb8dc5133c37c9ff6f3fd8b36af446f1dbcc25ab6",""]],template:function(n,s){if(1&n&&(e.TgZ(0,"div",0,1)(2,"div",2)(3,"a",3),e._UZ(4,"i",4),e.qZA()(),e.TgZ(5,"h3",5),e._uU(6,"Module reference"),e.qZA(),e.TgZ(7,"p"),e._uU(8,"Nest provides the "),e.TgZ(9,"code"),e._uU(10,"ModuleRef"),e.qZA(),e._uU(11," class to navigate the internal list of providers and obtain a reference to any provider using its injection token as a lookup key. The "),e.TgZ(12,"code"),e._uU(13,"ModuleRef"),e.qZA(),e._uU(14," class also provides a way to dynamically instantiate both static and scoped providers. "),e.TgZ(15,"code"),e._uU(16,"ModuleRef"),e.qZA(),e._uU(17," can be injected into a class in the normal way:"),e.qZA(),e.TgZ(18,"span",6),e._uU(19),e.ALo(20,"extension"),e._UZ(21,"app-tabs",null,7),e.qZA(),e.TgZ(23,"pre")(24,"code",8),e._uU(25,"\n@Injectable()\nexport class CatsService {\n constructor(private moduleRef: ModuleRef) {}\n}\n"),e.qZA()(),e.TgZ(26,"pre")(27,"code",8),e._uU(28,"\n@Injectable()\n@Dependencies(ModuleRef)\nexport class CatsService {\n constructor(moduleRef) {\n this.moduleRef = moduleRef;\n }\n}\n"),e.qZA()(),e.TgZ(29,"blockquote",9)(30,"strong"),e._uU(31,"Hint"),e.qZA(),e._uU(32," The "),e.TgZ(33,"code"),e._uU(34,"ModuleRef"),e.qZA(),e._uU(35," class is imported from the "),e.TgZ(36,"code"),e._uU(37,"@nestjs/core"),e.qZA(),e._uU(38," package.\n"),e.qZA(),e.TgZ(39,"h4",10)(40,"span"),e._uU(41,"Retrieving instances"),e.qZA()(),e.TgZ(42,"p"),e._uU(43,"The "),e.TgZ(44,"code"),e._uU(45,"ModuleRef"),e.qZA(),e._uU(46," instance (hereafter we'll refer to it as the "),e.TgZ(47,"strong"),e._uU(48,"module reference"),e.qZA(),e._uU(49,") has a "),e.TgZ(50,"code"),e._uU(51,"get()"),e.qZA(),e._uU(52," method. This method retrieves a provider, controller, or injectable (e.g., guard, interceptor, etc.) that exists (has been instantiated) in the "),e.TgZ(53,"strong"),e._uU(54,"current"),e.qZA(),e._uU(55," module using its injection token/class name."),e.qZA(),e.TgZ(56,"span",6),e._uU(57),e.ALo(58,"extension"),e._UZ(59,"app-tabs",null,11),e.qZA(),e.TgZ(61,"pre")(62,"code",8),e._uU(63,"\n@Injectable()\nexport class CatsService implements OnModuleInit {\n private service: Service;\n constructor(private moduleRef: ModuleRef) {}\n\n onModuleInit() {\n this.service = this.moduleRef.get(Service);\n }\n}\n"),e.qZA()(),e.TgZ(64,"pre")(65,"code",8),e._uU(66,"\n@Injectable()\n@Dependencies(ModuleRef)\nexport class CatsService {\n constructor(moduleRef) {\n this.moduleRef = moduleRef;\n }\n\n onModuleInit() {\n this.service = this.moduleRef.get(Service);\n }\n}\n"),e.qZA()(),e.TgZ(67,"blockquote",12)(68,"strong"),e._uU(69,"Warning"),e.qZA(),e._uU(70," You can't retrieve scoped providers (transient or request-scoped) with the "),e.TgZ(71,"code"),e._uU(72,"get()"),e.qZA(),e._uU(73," method. Instead, use the technique described "),e.TgZ(74,"a",13),e._uU(75,"below"),e.qZA(),e._uU(76,". Learn how to control scopes "),e.TgZ(77,"a",14),e._uU(78,"here"),e.qZA(),e._uU(79,".\n"),e.qZA(),e.TgZ(80,"p"),e._uU(81,"To retrieve a provider from the global context (for example, if the provider has been injected in a different module), pass the "),e.TgZ(82,"code"),e._uU(83),e.qZA(),e._uU(84," option as a second argument to "),e.TgZ(85,"code"),e._uU(86,"get()"),e.qZA(),e._uU(87,"."),e.qZA(),e.TgZ(88,"pre")(89,"code",8),e._uU(90,"\nthis.moduleRef.get(Service, { strict: false });\n"),e.qZA()(),e.TgZ(91,"h4",15)(92,"span"),e._uU(93,"Resolving scoped providers"),e.qZA()(),e.TgZ(94,"p"),e._uU(95,"To dynamically resolve a scoped provider (transient or request-scoped), use the "),e.TgZ(96,"code"),e._uU(97,"resolve()"),e.qZA(),e._uU(98," method, passing the provider's injection token as an argument."),e.qZA(),e.TgZ(99,"span",6),e._uU(100),e.ALo(101,"extension"),e._UZ(102,"app-tabs",null,16),e.qZA(),e.TgZ(104,"pre")(105,"code",8),e._uU(106,"\n@Injectable()\nexport class CatsService implements OnModuleInit {\n private transientService: TransientService;\n constructor(private moduleRef: ModuleRef) {}\n\n async onModuleInit() {\n this.transientService = await this.moduleRef.resolve(TransientService);\n }\n}\n"),e.qZA()(),e.TgZ(107,"pre")(108,"code",8),e._uU(109,"\n@Injectable()\n@Dependencies(ModuleRef)\nexport class CatsService {\n constructor(moduleRef) {\n this.moduleRef = moduleRef;\n }\n\n async onModuleInit() {\n this.transientService = await this.moduleRef.resolve(TransientService);\n }\n}\n"),e.qZA()(),e.TgZ(110,"p"),e._uU(111,"The "),e.TgZ(112,"code"),e._uU(113,"resolve()"),e.qZA(),e._uU(114," method returns a unique instance of the provider, from its own "),e.TgZ(115,"strong"),e._uU(116,"DI container sub-tree"),e.qZA(),e._uU(117,". Each sub-tree has a unique "),e.TgZ(118,"strong"),e._uU(119,"context identifier"),e.qZA(),e._uU(120,". Thus, if you call this method more than once and compare instance references, you will see that they are not equal."),e.qZA(),e.TgZ(121,"span",6),e._uU(122),e.ALo(123,"extension"),e._UZ(124,"app-tabs",null,17),e.qZA(),e.TgZ(126,"pre")(127,"code",8),e._uU(128,"\n@Injectable()\nexport class CatsService implements OnModuleInit {\n constructor(private moduleRef: ModuleRef) {}\n\n async onModuleInit() {\n const transientServices = await Promise.all([\n this.moduleRef.resolve(TransientService),\n this.moduleRef.resolve(TransientService),\n ]);\n console.log(transientServices[0] === transientServices[1]); // false\n }\n}\n"),e.qZA()(),e.TgZ(129,"pre")(130,"code",8),e._uU(131,"\n@Injectable()\n@Dependencies(ModuleRef)\nexport class CatsService {\n constructor(moduleRef) {\n this.moduleRef = moduleRef;\n }\n\n async onModuleInit() {\n const transientServices = await Promise.all([\n this.moduleRef.resolve(TransientService),\n this.moduleRef.resolve(TransientService),\n ]);\n console.log(transientServices[0] === transientServices[1]); // false\n }\n}\n"),e.qZA()(),e.TgZ(132,"p"),e._uU(133,"To generate a single instance across multiple "),e.TgZ(134,"code"),e._uU(135,"resolve()"),e.qZA(),e._uU(136," calls, and ensure they share the same generated DI container sub-tree, you can pass a context identifier to the "),e.TgZ(137,"code"),e._uU(138,"resolve()"),e.qZA(),e._uU(139," method. Use the "),e.TgZ(140,"code"),e._uU(141,"ContextIdFactory"),e.qZA(),e._uU(142," class to generate a context identifier. This class provides a "),e.TgZ(143,"code"),e._uU(144,"create()"),e.qZA(),e._uU(145," method that returns an appropriate unique identifier."),e.qZA(),e.TgZ(146,"span",6),e._uU(147),e.ALo(148,"extension"),e._UZ(149,"app-tabs",null,18),e.qZA(),e.TgZ(151,"pre")(152,"code",8),e._uU(153,"\n@Injectable()\nexport class CatsService implements OnModuleInit {\n constructor(private moduleRef: ModuleRef) {}\n\n async onModuleInit() {\n const contextId = ContextIdFactory.create();\n const transientServices = await Promise.all([\n this.moduleRef.resolve(TransientService, contextId),\n this.moduleRef.resolve(TransientService, contextId),\n ]);\n console.log(transientServices[0] === transientServices[1]); // true\n }\n}\n"),e.qZA()(),e.TgZ(154,"pre")(155,"code",8),e._uU(156,"\n@Injectable()\n@Dependencies(ModuleRef)\nexport class CatsService {\n constructor(moduleRef) {\n this.moduleRef = moduleRef;\n }\n\n async onModuleInit() {\n const contextId = ContextIdFactory.create();\n const transientServices = await Promise.all([\n this.moduleRef.resolve(TransientService, contextId),\n this.moduleRef.resolve(TransientService, contextId),\n ]);\n console.log(transientServices[0] === transientServices[1]); // true\n }\n}\n"),e.qZA()(),e.TgZ(157,"blockquote",9)(158,"strong"),e._uU(159,"Hint"),e.qZA(),e._uU(160," The "),e.TgZ(161,"code"),e._uU(162,"ContextIdFactory"),e.qZA(),e._uU(163," class is imported from the "),e.TgZ(164,"code"),e._uU(165,"@nestjs/core"),e.qZA(),e._uU(166," package.\n"),e.qZA(),e.TgZ(167,"h4",19)(168,"span"),e._uU(169,"Registering "),e.TgZ(170,"code"),e._uU(171,"REQUEST"),e.qZA(),e._uU(172," provider"),e.qZA()(),e.TgZ(173,"p"),e._uU(174,"Manually generated context identifiers (with "),e.TgZ(175,"code"),e._uU(176,"ContextIdFactory.create()"),e.qZA(),e._uU(177,") represent DI sub-trees in which "),e.TgZ(178,"code"),e._uU(179,"REQUEST"),e.qZA(),e._uU(180," provider is "),e.TgZ(181,"code"),e._uU(182,"undefined"),e.qZA(),e._uU(183," as they are not instantiated and managed by the Nest dependency injection system."),e.qZA(),e.TgZ(184,"p"),e._uU(185,"To register a custom "),e.TgZ(186,"code"),e._uU(187,"REQUEST"),e.qZA(),e._uU(188," object for a manually created DI sub-tree, use the "),e.TgZ(189,"code"),e._uU(190,"ModuleRef#registerRequestByContextId()"),e.qZA(),e._uU(191," method, as follows:"),e.qZA(),e.TgZ(192,"pre")(193,"code",8),e._uU(194,"\nconst contextId = ContextIdFactory.create();\nthis.moduleRef.registerRequestByContextId(/* YOUR_REQUEST_OBJECT */, contextId);\n"),e.qZA()(),e.TgZ(195,"h4",20)(196,"span"),e._uU(197,"Getting current sub-tree"),e.qZA()(),e.TgZ(198,"p"),e._uU(199,"Occasionally, you may want to resolve an instance of a request-scoped provider within a "),e.TgZ(200,"strong"),e._uU(201,"request context"),e.qZA(),e._uU(202,". Let's say that "),e.TgZ(203,"code"),e._uU(204,"CatsService"),e.qZA(),e._uU(205," is request-scoped and you want to resolve the "),e.TgZ(206,"code"),e._uU(207,"CatsRepository"),e.qZA(),e._uU(208," instance which is also marked as a request-scoped provider. In order to share the same DI container sub-tree, you must obtain the current context identifier instead of generating a new one (e.g., with the "),e.TgZ(209,"code"),e._uU(210,"ContextIdFactory.create()"),e.qZA(),e._uU(211," function, as shown above). To obtain the current context identifier, start by injecting the request object using "),e.TgZ(212,"code"),e._uU(213,"@Inject()"),e.qZA(),e._uU(214," decorator."),e.qZA(),e.TgZ(215,"span",6),e._uU(216),e.ALo(217,"extension"),e._UZ(218,"app-tabs",null,21),e.qZA(),e.TgZ(220,"pre")(221,"code",8),e._uU(222,"\n@Injectable()\nexport class CatsService {\n constructor(\n @Inject(REQUEST) private request: Record<string, unknown>,\n ) {}\n}\n"),e.qZA()(),e.TgZ(223,"pre")(224,"code",8),e._uU(225,"\n@Injectable()\n@Dependencies(REQUEST)\nexport class CatsService {\n constructor(request) {\n this.request = request;\n }\n}\n"),e.qZA()(),e.TgZ(226,"blockquote",9)(227,"strong"),e._uU(228,"Hint"),e.qZA(),e._uU(229," Learn more about the request provider "),e.TgZ(230,"a",22),e._uU(231,"here"),e.qZA(),e._uU(232,".\n"),e.qZA(),e.TgZ(233,"p"),e._uU(234,"Now, use the "),e.TgZ(235,"code"),e._uU(236,"getByRequest()"),e.qZA(),e._uU(237," method of the "),e.TgZ(238,"code"),e._uU(239,"ContextIdFactory"),e.qZA(),e._uU(240," class to create a context id based on the request object, and pass this to the "),e.TgZ(241,"code"),e._uU(242,"resolve()"),e.qZA(),e._uU(243," call:"),e.qZA(),e.TgZ(244,"pre")(245,"code",8),e._uU(246,"\nconst contextId = ContextIdFactory.getByRequest(this.request);\nconst catsRepository = await this.moduleRef.resolve(CatsRepository, contextId);\n"),e.qZA()(),e.TgZ(247,"h4",23)(248,"span"),e._uU(249,"Instantiating custom classes dynamically"),e.qZA()(),e.TgZ(250,"p"),e._uU(251,"To dynamically instantiate a class that "),e.TgZ(252,"strong"),e._uU(253,"wasn't previously registered"),e.qZA(),e._uU(254," as a "),e.TgZ(255,"strong"),e._uU(256,"provider"),e.qZA(),e._uU(257,", use the module reference's "),e.TgZ(258,"code"),e._uU(259,"create()"),e.qZA(),e._uU(260," method."),e.qZA(),e.TgZ(261,"span",6),e._uU(262),e.ALo(263,"extension"),e._UZ(264,"app-tabs",null,24),e.qZA(),e.TgZ(266,"pre")(267,"code",8),e._uU(268,"\n@Injectable()\nexport class CatsService implements OnModuleInit {\n private catsFactory: CatsFactory;\n constructor(private moduleRef: ModuleRef) {}\n\n async onModuleInit() {\n this.catsFactory = await this.moduleRef.create(CatsFactory);\n }\n}\n"),e.qZA()(),e.TgZ(269,"pre")(270,"code",8),e._uU(271,"\n@Injectable()\n@Dependencies(ModuleRef)\nexport class CatsService {\n constructor(moduleRef) {\n this.moduleRef = moduleRef;\n }\n\n async onModuleInit() {\n this.catsFactory = await this.moduleRef.create(CatsFactory);\n }\n}\n"),e.qZA()(),e.TgZ(272,"p"),e._uU(273,"This technique enables you to conditionally instantiate different classes outside of the framework container."),e.qZA(),e.TgZ(274,"p"),e._UZ(275,"app-banner-devtools"),e.qZA()()),2&n){const a=e.MAs(22),r=e.MAs(60),i=e.MAs(103),u=e.MAs(125),_=e.MAs(150),g=e.MAs(219),Z=e.MAs(265);e.xp6(19),e.hij(" ",e.xi3(20,37,"cats.service",a.isJsActive),"\n"),e.xp6(4),e.ekj("hide",a.isJsActive),e.xp6(3),e.ekj("hide",!a.isJsActive),e.xp6(31),e.hij(" ",e.xi3(58,40,"cats.service",r.isJsActive),"\n"),e.xp6(4),e.ekj("hide",r.isJsActive),e.xp6(3),e.ekj("hide",!r.isJsActive),e.xp6(19),e.AsE("","{"," strict: false ","}",""),e.xp6(17),e.hij(" ",e.xi3(101,43,"cats.service",i.isJsActive),"\n"),e.xp6(4),e.ekj("hide",i.isJsActive),e.xp6(3),e.ekj("hide",!i.isJsActive),e.xp6(15),e.hij(" ",e.xi3(123,46,"cats.service",u.isJsActive),"\n"),e.xp6(4),e.ekj("hide",u.isJsActive),e.xp6(3),e.ekj("hide",!u.isJsActive),e.xp6(18),e.hij(" ",e.xi3(148,49,"cats.service",_.isJsActive),"\n"),e.xp6(4),e.ekj("hide",_.isJsActive),e.xp6(3),e.ekj("hide",!_.isJsActive),e.xp6(62),e.hij(" ",e.xi3(217,52,"cats.service",g.isJsActive),"\n"),e.xp6(4),e.ekj("hide",g.isJsActive),e.xp6(3),e.ekj("hide",!g.isJsActive),e.xp6(39),e.hij(" ",e.xi3(263,55,"cats.service",Z.isJsActive),"\n"),e.xp6(4),e.ekj("hide",Z.isJsActive),e.xp6(3),e.ekj("hide",!Z.isJsActive)}},dependencies:[h.n,l.U,v.E,p.rH,U.F],encapsulation:2,changeDetection:0})}return t})();var M=c(8427);const I=[{path:"dynamic-modules",component:k,data:{title:"Dynamic modules"}},{path:"dependency-injection",redirectTo:"custom-providers"},{path:"custom-providers",component:C,data:{title:"Custom providers"}},{path:"platform-agnosticism",component:(()=>{class t extends d.y{static \u0275fac=function(){let o;return function(s){return(o||(o=e.n5z(t)))(s||t)}}();static \u0275cmp=e.Xpm({type:t,selectors:[["app-platform-agnosticism"]],features:[e.qOj],decls:41,vars:0,consts:[[1,"content"],["contentReference",""],[1,"github-links"],["href","https://github.com/ChuTingzj/docs.nestjs.zh-cn.com/tree/master/content/fundamentals/platform-agnosticism.md","aria-label","Suggest Edits","title","Suggest Edits"],[1,"fas","fa-edit"],["id","platform-agnosticism"],["appAnchor","","id","build-once-use-everywhere"],["routerLink","/microservices/basics"],["routerLink","/websockets/gateways"],["routerLink","/graphql/quick-start"],["routerLink","/application-context"]],template:function(n,s){1&n&&(e.TgZ(0,"div",0,1)(2,"div",2)(3,"a",3),e._UZ(4,"i",4),e.qZA()(),e.TgZ(5,"h3",5),e._uU(6,"Platform agnosticism"),e.qZA(),e.TgZ(7,"p"),e._uU(8,"Nest is a platform-agnostic framework. This means you can develop "),e.TgZ(9,"strong"),e._uU(10,"reusable logical parts"),e.qZA(),e._uU(11," that can be used across different types of applications. For example, most components can be re-used without change across different underlying HTTP server frameworks (e.g., Express and Fastify), and even across different "),e.TgZ(12,"em"),e._uU(13,"types"),e.qZA(),e._uU(14," of applications (e.g., HTTP server frameworks, Microservices with different transport layers, and Web Sockets)."),e.qZA(),e.TgZ(15,"h4",6)(16,"span"),e._uU(17,"Build once, use everywhere"),e.qZA()(),e.TgZ(18,"p"),e._uU(19,"The "),e.TgZ(20,"strong"),e._uU(21,"Overview"),e.qZA(),e._uU(22," section of the documentation primarily shows coding techniques using HTTP server frameworks (e.g., apps providing a REST API or providing an MVC-style server-side rendered app). However, all those building blocks can be used on top of different transport layers ("),e.TgZ(23,"a",7),e._uU(24,"microservices"),e.qZA(),e._uU(25," or "),e.TgZ(26,"a",8),e._uU(27,"websockets"),e.qZA(),e._uU(28,")."),e.qZA(),e.TgZ(29,"p"),e._uU(30,"Furthermore, Nest comes with a dedicated "),e.TgZ(31,"a",9),e._uU(32,"GraphQL"),e.qZA(),e._uU(33," module. You can use GraphQL as your API layer interchangeably with providing a REST API."),e.qZA(),e.TgZ(34,"p"),e._uU(35,"In addition, the "),e.TgZ(36,"a",10),e._uU(37,"application context"),e.qZA(),e._uU(38," feature helps to create any kind of Node.js application - including things like CRON jobs and CLI apps - on top of Nest."),e.qZA(),e.TgZ(39,"p"),e._uU(40,"Nest aspires to be a full-fledged platform for Node.js apps that brings a higher-level of modularity and reusability to your applications. Build once, use everywhere!"),e.qZA()())},dependencies:[l.U,p.rH],encapsulation:2,changeDetection:0})}return t})(),data:{title:"Platform agnosticism"}},{path:"async-components",redirectTo:"async-providers"},{path:"async-providers",component:w,data:{title:"Async providers"}},{path:"module-ref",component:S,data:{title:"Module reference"}},{path:"lazy-loading-modules",component:(()=>{class t extends d.y{static \u0275fac=function(){let o;return function(s){return(o||(o=e.n5z(t)))(s||t)}}();static \u0275cmp=e.Xpm({type:t,selectors:[["app-lazy-loading"]],features:[e.qOj],decls:219,vars:8,consts:[[1,"content"],["contentReference",""],[1,"github-links"],["href","https://github.com/ChuTingzj/docs.nestjs.zh-cn.com/tree/master/content/fundamentals/lazy-loading-modules.md","aria-label","Suggest Edits","title","Suggest Edits"],[1,"fas","fa-edit"],["id","lazy-loading-modules"],[1,"info"],[1,"warning"],["rel","nofollow","target","_blank","href","https://docs.nestjs.com/fundamentals/lifecycle-events"],["appAnchor","","id","getting-started"],[1,"filename"],["app51fdec8cdfe85e8b5c9e0df09512925ef97d2b9d",""],[1,"language-typescript"],[1,"language-bash"],["routerLink","/fundamentals/module-ref"],[1,"language-json"],["rel","nofollow","target","_blank","href","https://webpack.js.org/guides/code-splitting/"],["appAnchor","","id","lazy-loading-controllers-gateways-and-resolvers"],[1,"error"],["routerLink","/graphql/resolvers"],["routerLink","/websockets/gateways"],["appAnchor","","id","common-use-cases"]],template:function(n,s){if(1&n&&(e.TgZ(0,"div",0,1)(2,"div",2)(3,"a",3),e._UZ(4,"i",4),e.qZA()(),e.TgZ(5,"h3",5),e._uU(6,"Lazy-loading modules"),e.qZA(),e.TgZ(7,"p"),e._uU(8,"By default, modules are eagerly loaded, which means that as soon as the application loads, so do all the modules, whether or not they are immediately necessary. While this is fine for most applications, it may become a bottleneck for apps/workers running in the "),e.TgZ(9,"strong"),e._uU(10,"serverless environment"),e.qZA(),e._uU(11,', where the startup latency ("cold start") is crucial.'),e.qZA(),e.TgZ(12,"p"),e._uU(13,'Lazy loading can help decrease bootstrap time by loading only modules required by the specific serverless function invocation. In addition, you could also load other modules asynchronously once the serverless function is "warm" to speed-up the bootstrap time for subsequent calls even further (deferred modules registration).'),e.qZA(),e.TgZ(14,"blockquote",6)(15,"strong"),e._uU(16,"Hint"),e.qZA(),e._uU(17," If you're familiar with the "),e.TgZ(18,"strong"),e._uU(19,"Angular"),e.qZA(),e._uU(20,' framework, you might have seen the "lazy-loading modules" term before. Be aware that this technique is '),e.TgZ(21,"strong"),e._uU(22,"functionally different"),e.qZA(),e._uU(23," in Nest and so think about this as an entirely different feature that shares similar naming conventions.\n"),e.qZA(),e.TgZ(24,"blockquote",7)(25,"strong"),e._uU(26,"Warning"),e.qZA(),e._uU(27," Do note that "),e.TgZ(28,"a",8),e._uU(29,"lifecycle hooks methods"),e.qZA(),e._uU(30," are not invoked in lazy loaded modules and services.\n"),e.qZA(),e.TgZ(31,"h4",9)(32,"span"),e._uU(33,"Getting started"),e.qZA()(),e.TgZ(34,"p"),e._uU(35,"To load modules on-demand, Nest provides the "),e.TgZ(36,"code"),e._uU(37,"LazyModuleLoader"),e.qZA(),e._uU(38," class that can be injected into a class in the normal way:"),e.qZA(),e.TgZ(39,"span",10),e._uU(40),e.ALo(41,"extension"),e._UZ(42,"app-tabs",null,11),e.qZA(),e.TgZ(44,"pre")(45,"code",12),e._uU(46,"\n@Injectable()\nexport class CatsService {\n constructor(private lazyModuleLoader: LazyModuleLoader) {}\n}\n"),e.qZA()(),e.TgZ(47,"pre")(48,"code",12),e._uU(49,"\n@Injectable()\n@Dependencies(LazyModuleLoader)\nexport class CatsService {\n constructor(lazyModuleLoader) {\n this.lazyModuleLoader = lazyModuleLoader;\n }\n}\n"),e.qZA()(),e.TgZ(50,"blockquote",6)(51,"strong"),e._uU(52,"Hint"),e.qZA(),e._uU(53," The "),e.TgZ(54,"code"),e._uU(55,"LazyModuleLoader"),e.qZA(),e._uU(56," class is imported from the "),e.TgZ(57,"code"),e._uU(58,"@nestjs/core"),e.qZA(),e._uU(59," package.\n"),e.qZA(),e.TgZ(60,"p"),e._uU(61,"Alternatively, you can obtain a reference to the "),e.TgZ(62,"code"),e._uU(63,"LazyModuleLoader"),e.qZA(),e._uU(64," provider from within your application bootstrap file ("),e.TgZ(65,"code"),e._uU(66,"main.ts"),e.qZA(),e._uU(67,"), as follows:"),e.qZA(),e.TgZ(68,"pre")(69,"code",12),e._uU(70,'\n// "app" represents a Nest application instance\nconst lazyModuleLoader = app.get(LazyModuleLoader);\n'),e.qZA()(),e.TgZ(71,"p"),e._uU(72,"With this in place, you can now load any module using the following construction:"),e.qZA(),e.TgZ(73,"pre")(74,"code",12),e._uU(75,"\nconst { LazyModule } = await import('./lazy.module');\nconst moduleRef = await this.lazyModuleLoader.load(() => LazyModule);\n"),e.qZA()(),e.TgZ(76,"blockquote",6)(77,"strong"),e._uU(78,"Hint"),e.qZA(),e._uU(79,' "Lazy-loaded" modules are '),e.TgZ(80,"strong"),e._uU(81,"cached"),e.qZA(),e._uU(82," upon the first "),e.TgZ(83,"code"),e._uU(84,"LazyModuleLoader#load"),e.qZA(),e._uU(85," method invocation. That means, each consecutive attempt to load "),e.TgZ(86,"code"),e._uU(87,"LazyModule"),e.qZA(),e._uU(88," will be "),e.TgZ(89,"strong"),e._uU(90,"very fast"),e.qZA(),e._uU(91," and will return a cached instance, instead of loading the module again.\n"),e.TgZ(92,"pre")(93,"code",13),e._uU(94,'\nLoad "LazyModule" attempt: 1\ntime: 2.379ms\nLoad "LazyModule" attempt: 2\ntime: 0.294ms\nLoad "LazyModule" attempt: 3\ntime: 0.303ms\n'),e.qZA()(),e.TgZ(95,"p"),e._uU(96,'Also, "lazy-loaded" modules share the same modules graph as those eagerly loaded on the application bootstrap as well as any other lazy modules registered later in your app.'),e.qZA()(),e.TgZ(97,"p"),e._uU(98,"Where "),e.TgZ(99,"code"),e._uU(100,"lazy.module.ts"),e.qZA(),e._uU(101," is a TypeScript file that exports a "),e.TgZ(102,"strong"),e._uU(103,"regular Nest module"),e.qZA(),e._uU(104," (no extra changes are required)."),e.qZA(),e.TgZ(105,"p"),e._uU(106,"The "),e.TgZ(107,"code"),e._uU(108,"LazyModuleLoader#load"),e.qZA(),e._uU(109," method returns the "),e.TgZ(110,"a",14),e._uU(111,"module reference"),e.qZA(),e._uU(112," (of "),e.TgZ(113,"code"),e._uU(114,"LazyModule"),e.qZA(),e._uU(115,") that lets you navigate the internal list of providers and obtain a reference to any provider using its injection token as a lookup key."),e.qZA(),e.TgZ(116,"p"),e._uU(117,"For example, let's say we have a "),e.TgZ(118,"code"),e._uU(119,"LazyModule"),e.qZA(),e._uU(120," with the following definition:"),e.qZA(),e.TgZ(121,"pre")(122,"code",12),e._uU(123,"\n@Module({\n providers: [LazyService],\n exports: [LazyService],\n})\nexport class LazyModule {}\n"),e.qZA()(),e.TgZ(124,"blockquote",6)(125,"strong"),e._uU(126,"Hint"),e.qZA(),e._uU(127," Lazy-loaded modules cannot be registered as "),e.TgZ(128,"strong"),e._uU(129,"global modules"),e.qZA(),e._uU(130," as it simply makes no sense (since they are registered lazily, on-demand when all the statically registered modules have been already instantiated). Likewise, registered "),e.TgZ(131,"strong"),e._uU(132,"global enhancers"),e.qZA(),e._uU(133," (guards/interceptors/etc.) "),e.TgZ(134,"strong"),e._uU(135,"will not work"),e.qZA(),e._uU(136," properly either.\n"),e.qZA(),e.TgZ(137,"p"),e._uU(138,"With this, we could obtain a reference to the "),e.TgZ(139,"code"),e._uU(140,"LazyService"),e.qZA(),e._uU(141," provider, as follows:"),e.qZA(),e.TgZ(142,"pre")(143,"code",12),e._uU(144,"\nconst { LazyModule } = await import('./lazy.module');\nconst moduleRef = await this.lazyModuleLoader.load(() => LazyModule);\n\nconst { LazyService } = await import('./lazy.service');\nconst lazyService = moduleRef.get(LazyService);\n"),e.qZA()(),e.TgZ(145,"blockquote",7)(146,"strong"),e._uU(147,"Warning"),e.qZA(),e._uU(148," If you use "),e.TgZ(149,"strong"),e._uU(150,"Webpack"),e.qZA(),e._uU(151,", make sure to update your "),e.TgZ(152,"code"),e._uU(153,"tsconfig.json"),e.qZA(),e._uU(154," file - setting "),e.TgZ(155,"code"),e._uU(156,"compilerOptions.module"),e.qZA(),e._uU(157," to "),e.TgZ(158,"code"),e._uU(159,'"esnext"'),e.qZA(),e._uU(160," and adding "),e.TgZ(161,"code"),e._uU(162,"compilerOptions.moduleResolution"),e.qZA(),e._uU(163," property with "),e.TgZ(164,"code"),e._uU(165,'"node"'),e.qZA(),e._uU(166," as a value:\n"),e.TgZ(167,"pre")(168,"code",15),e._uU(169,'\n{\n "compilerOptions": {\n "module": "esnext",\n "moduleResolution": "node",\n ...\n }\n}\n'),e.qZA()(),e.TgZ(170,"p"),e._uU(171,"With these options set up, you'll be able to leverage the "),e.TgZ(172,"a",16),e._uU(173,"code splitting"),e.qZA(),e._uU(174," feature."),e.qZA()(),e.TgZ(175,"h4",17)(176,"span"),e._uU(177,"Lazy-loading controllers, gateways, and resolvers"),e.qZA()(),e.TgZ(178,"p"),e._uU(179,"Since controllers (or resolvers in GraphQL applications) in Nest represent sets of routes/paths/topics (or queries/mutations), you "),e.TgZ(180,"strong"),e._uU(181,"cannot lazy load them"),e.qZA(),e._uU(182," using the "),e.TgZ(183,"code"),e._uU(184,"LazyModuleLoader"),e.qZA(),e._uU(185," class."),e.qZA(),e.TgZ(186,"blockquote",18)(187,"strong"),e._uU(188,"Warning"),e.qZA(),e._uU(189," Controllers, "),e.TgZ(190,"a",19),e._uU(191,"resolvers"),e.qZA(),e._uU(192,", and "),e.TgZ(193,"a",20),e._uU(194,"gateways"),e.qZA(),e._uU(195," registered inside lazy-loaded modules will not behave as expected. Similarly, you cannot register middleware functions (by implementing the "),e.TgZ(196,"code"),e._uU(197,"MiddlewareConsumer"),e.qZA(),e._uU(198," interface) on-demand.\n"),e.qZA(),e.TgZ(199,"p"),e._uU(200,"For example, let's say you're building a REST API (HTTP application) with a Fastify driver under the hood (using the "),e.TgZ(201,"code"),e._uU(202,"@nestjs/platform-fastify"),e.qZA(),e._uU(203," package). Fastify does not let you register routes after the application is ready/successfully listening to messages. That means even if we analyzed route mappings registered in the module's controllers, all lazy-loaded routes wouldn't be accessible since there is no way to register them at runtime."),e.qZA(),e.TgZ(204,"p"),e._uU(205,"Likewise, some transport strategies we provide as part of the "),e.TgZ(206,"code"),e._uU(207,"@nestjs/microservices"),e.qZA(),e._uU(208," package (including Kafka, gRPC, or RabbitMQ) require to subscribe/listen to specific topics/channels before the connection is established. Once your application starts listening to messages, the framework would not be able to subscribe/listen to new topics."),e.qZA(),e.TgZ(209,"p"),e._uU(210,"Lastly, the "),e.TgZ(211,"code"),e._uU(212,"@nestjs/graphql"),e.qZA(),e._uU(213," package with the code first approach enabled automatically generates the GraphQL schema on-the-fly based on the metadata. That means, it requires all classes to be loaded beforehand. Otherwise, it would not be doable to create the appropriate, valid schema."),e.qZA(),e.TgZ(214,"h4",21)(215,"span"),e._uU(216,"Common use-cases"),e.qZA()(),e.TgZ(217,"p"),e._uU(218,"Most commonly, you will see lazy loaded modules in situations when your worker/cron job/lambda & serverless function/webhook must trigger different services (different logic) based on the input arguments (route path/date/query parameters, etc.). On the other hand, lazy-loading modules may not make too much sense for monolithic applications, where the startup time is rather irrelevant."),e.qZA()()),2&n){const a=e.MAs(43);e.xp6(40),e.hij(" ",e.xi3(41,5,"cats.service",a.isJsActive),"\n"),e.xp6(4),e.ekj("hide",a.isJsActive),e.xp6(3),e.ekj("hide",!a.isJsActive)}},dependencies:[h.n,l.U,p.rH,U.F],encapsulation:2,changeDetection:0})}return t})(),data:{title:"Lazy-loading modules"}},{path:"unit-testing",redirectTo:"testing"},{path:"e2e-testing",redirectTo:"testing"},{path:"testing",component:(()=>{class t extends d.y{static \u0275fac=function(){let o;return function(s){return(o||(o=e.n5z(t)))(s||t)}}();static \u0275cmp=e.Xpm({type:t,selectors:[["app-unit-testing"]],features:[e.qOj],decls:551,vars:24,consts:[[1,"content"],["contentReference",""],[1,"github-links"],["href","https://github.com/ChuTingzj/docs.nestjs.zh-cn.com/tree/master/content/fundamentals/unit-testing.md","aria-label","Suggest Edits","title","Suggest Edits"],[1,"fas","fa-edit"],["id","testing"],["rel","nofollow","target","_blank","href","https://github.com/facebook/jest"],["rel","nofollow","target","_blank","href","https://github.com/visionmedia/supertest"],["appAnchor","","id","installation"],[1,"language-bash"],["appAnchor","","id","unit-testing"],[1,"filename"],["app16d47c16cb42e61632043619a1169731dffbe087",""],[1,"language-typescript"],[1,"info"],["appAnchor","","id","testing-utilities"],["app666c220362dc1cf342390692f624b78fc86dcfeb",""],["routerLink","/fundamentals/module-ref"],[1,"warning"],["routerLink","/fundamentals/custom-providers"],["appAnchor","","id","auto-mocking"],["rel","nofollow","target","_blank","href","https://www.npmjs.com/package/jest-mock"],["rel","nofollow","target","_blank","href","https://github.com/golevelup/nestjs/tree/master/packages/testing"],["appAnchor","","id","end-to-end-testing"],["app9c6ee6e8823f2cd0b58409f5774320dc40ca1ae1",""],["routerLink","/techniques/performance"],[1,"language-ts"],["rel","nofollow","target","_blank","href","https://docs.nestjs.com/fundamentals/custom-providers"],["rel","nofollow","target","_blank","href","https://en.wikipedia.org/wiki/Fluent_interface"],["rel","nofollow","target","_blank","href","https://github.com/nestjs/nest/issues/4053#issuecomment-585612462"],["href","/fundamentals/module-ref"],["appAnchor","","id","overriding-globally-registered-enhancers"],["appAnchor","","id","testing-request-scoped-instances"],["routerLink","/fundamentals/injection-scopes"],["href","https://docs.nestjs.com/fundamentals/module-ref#resolving-scoped-providers"]],template:function(n,s){if(1&n&&(e.TgZ(0,"div",0,1)(2,"div",2)(3,"a",3),e._UZ(4,"i",4),e.qZA()(),e.TgZ(5,"h3",5),e._uU(6,"Testing"),e.qZA(),e.TgZ(7,"p"),e._uU(8,"Automated testing is considered an essential part of any serious software development effort. Automation makes it easy to repeat individual tests or test suites quickly and easily during development. This helps ensure that releases meet quality and performance goals. Automation helps increase coverage and provides a faster feedback loop to developers. Automation both increases the productivity of individual developers and ensures that tests are run at critical development lifecycle junctures, such as source code control check-in, feature integration, and version release."),e.qZA(),e.TgZ(9,"p"),e._uU(10,"Such tests often span a variety of types, including unit tests, end-to-end (e2e) tests, integration tests, and so on. While the benefits are unquestionable, it can be tedious to set them up. Nest strives to promote development best practices, including effective testing, so it includes features such as the following to help developers and teams build and automate tests. Nest:"),e.qZA(),e.TgZ(11,"ul")(12,"li"),e._uU(13,"automatically scaffolds default unit tests for components and e2e tests for applications"),e.qZA(),e.TgZ(14,"li"),e._uU(15,"provides default tooling (such as a test runner that builds an isolated module/application loader)"),e.qZA(),e.TgZ(16,"li"),e._uU(17,"provides integration with "),e.TgZ(18,"a",6),e._uU(19,"Jest"),e.qZA(),e._uU(20," and "),e.TgZ(21,"a",7),e._uU(22,"Supertest"),e.qZA(),e._uU(23," out-of-the-box, while remaining agnostic to testing tools"),e.qZA(),e.TgZ(24,"li"),e._uU(25,"makes the Nest dependency injection system available in the testing environment for easily mocking components"),e.qZA()(),e.TgZ(26,"p"),e._uU(27,"As mentioned, you can use any "),e.TgZ(28,"strong"),e._uU(29,"testing framework"),e.qZA(),e._uU(30," that you like, as Nest doesn't force any specific tooling. Simply replace the elements needed (such as the test runner), and you will still enjoy the benefits of Nest's ready-made testing facilities."),e.qZA(),e.TgZ(31,"h4",8)(32,"span"),e._uU(33,"Installation"),e.qZA()(),e.TgZ(34,"p"),e._uU(35,"To get started, first install the required package:"),e.qZA(),e.TgZ(36,"pre")(37,"code",9),e._uU(38,"\n$ npm i --save-dev @nestjs/testing\n"),e.qZA()(),e.TgZ(39,"h4",10)(40,"span"),e._uU(41,"Unit testing"),e.qZA()(),e.TgZ(42,"p"),e._uU(43,"In the following example, we test two classes: "),e.TgZ(44,"code"),e._uU(45,"CatsController"),e.qZA(),e._uU(46," and "),e.TgZ(47,"code"),e._uU(48,"CatsService"),e.qZA(),e._uU(49,". As mentioned, "),e.TgZ(50,"a",6),e._uU(51,"Jest"),e.qZA(),e._uU(52," is provided as the default testing framework. It serves as a test-runner and also provides assert functions and test-double utilities that help with mocking, spying, etc. In the following basic test, we manually instantiate these classes, and ensure that the controller and service fulfill their API contract."),e.qZA(),e.TgZ(53,"span",11),e._uU(54),e.ALo(55,"extension"),e._UZ(56,"app-tabs",null,12),e.qZA(),e.TgZ(58,"pre")(59,"code",13),e._uU(60,"\nimport { CatsController } from './cats.controller';\nimport { CatsService } from './cats.service';\n\ndescribe('CatsController', () => {\n let catsController: CatsController;\n let catsService: CatsService;\n\n beforeEach(() => {\n catsService = new CatsService();\n catsController = new CatsController(catsService);\n });\n\n describe('findAll', () => {\n it('should return an array of cats', async () => {\n const result = ['test'];\n jest.spyOn(catsService, 'findAll').mockImplementation(() => result);\n\n expect(await catsController.findAll()).toBe(result);\n });\n });\n});\n"),e.qZA()(),e.TgZ(61,"pre")(62,"code",13),e._uU(63,"\nimport { CatsController } from './cats.controller';\nimport { CatsService } from './cats.service';\n\ndescribe('CatsController', () => {\n let catsController;\n let catsService;\n\n beforeEach(() => {\n catsService = new CatsService();\n catsController = new CatsController(catsService);\n });\n\n describe('findAll', () => {\n it('should return an array of cats', async () => {\n const result = ['test'];\n jest.spyOn(catsService, 'findAll').mockImplementation(() => result);\n\n expect(await catsController.findAll()).toBe(result);\n });\n });\n});\n"),e.qZA()(),e.TgZ(64,"blockquote",14)(65,"strong"),e._uU(66,"Hint"),e.qZA(),e._uU(67," Keep your test files located near the classes they test. Testing files should have a "),e.TgZ(68,"code"),e._uU(69,".spec"),e.qZA(),e._uU(70," or "),e.TgZ(71,"code"),e._uU(72,".test"),e.qZA(),e._uU(73," suffix.\n"),e.qZA(),e.TgZ(74,"p"),e._uU(75,"Because the above sample is trivial, we aren't really testing anything Nest-specific. Indeed, we aren't even using dependency injection (notice that we pass an instance of "),e.TgZ(76,"code"),e._uU(77,"CatsService"),e.qZA(),e._uU(78," to our "),e.TgZ(79,"code"),e._uU(80,"catsController"),e.qZA(),e._uU(81,"). This form of testing - where we manually instantiate the classes being tested - is often called "),e.TgZ(82,"strong"),e._uU(83,"isolated testing"),e.qZA(),e._uU(84," as it is independent from the framework. Let's introduce some more advanced capabilities that help you test applications that make more extensive use of Nest features."),e.qZA(),e.TgZ(85,"h4",15)(86,"span"),e._uU(87,"Testing utilities"),e.qZA()(),e.TgZ(88,"p"),e._uU(89,"The "),e.TgZ(90,"code"),e._uU(91,"@nestjs/testing"),e.qZA(),e._uU(92," package provides a set of utilities that enable a more robust testing process. Let's rewrite the previous example using the built-in "),e.TgZ(93,"code"),e._uU(94,"Test"),e.qZA(),e._uU(95," class:"),e.qZA(),e.TgZ(96,"span",11),e._uU(97),e.ALo(98,"extension"),e._UZ(99,"app-tabs",null,16),e.qZA(),e.TgZ(101,"pre")(102,"code",13),e._uU(103,"\nimport { Test } from '@nestjs/testing';\nimport { CatsController } from './cats.controller';\nimport { CatsService } from './cats.service';\n\ndescribe('CatsController', () => {\n let catsController: CatsController;\n let catsService: CatsService;\n\n beforeEach(async () => {\n const moduleRef = await Test.createTestingModule({\n controllers: [CatsController],\n providers: [CatsService],\n }).compile();\n\n catsService = moduleRef.get<CatsService>(CatsService);\n catsController = moduleRef.get<CatsController>(CatsController);\n });\n\n describe('findAll', () => {\n it('should return an array of cats', async () => {\n const result = ['test'];\n jest.spyOn(catsService, 'findAll').mockImplementation(() => result);\n\n expect(await catsController.findAll()).toBe(result);\n });\n });\n});\n"),e.qZA()(),e.TgZ(104,"pre")(105,"code",13),e._uU(106,"\nimport { Test } from '@nestjs/testing';\nimport { CatsController } from './cats.controller';\nimport { CatsService } from './cats.service';\n\ndescribe('CatsController', () => {\n let catsController;\n let catsService;\n\n beforeEach(async () => {\n const moduleRef = await Test.createTestingModule({\n controllers: [CatsController],\n providers: [CatsService],\n }).compile();\n\n catsService = moduleRef.get(CatsService);\n catsController = moduleRef.get(CatsController);\n });\n\n describe('findAll', () => {\n it('should return an array of cats', async () => {\n const result = ['test'];\n jest.spyOn(catsService, 'findAll').mockImplementation(() => result);\n\n expect(await catsController.findAll()).toBe(result);\n });\n });\n});\n"),e.qZA()(),e.TgZ(107,"p"),e._uU(108,"The "),e.TgZ(109,"code"),e._uU(110,"Test"),e.qZA(),e._uU(111," class is useful for providing an application execution context that essentially mocks the full Nest runtime, but gives you hooks that make it easy to manage class instances, including mocking and overriding. The "),e.TgZ(112,"code"),e._uU(113,"Test"),e.qZA(),e._uU(114," class has a "),e.TgZ(115,"code"),e._uU(116,"createTestingModule()"),e.qZA(),e._uU(117," method that takes a module metadata object as its argument (the same object you pass to the "),e.TgZ(118,"code"),e._uU(119,"@Module()"),e.qZA(),e._uU(120," decorator). This method returns a "),e.TgZ(121,"code"),e._uU(122,"TestingModule"),e.qZA(),e._uU(123," instance which in turn provides a few methods. For unit tests, the important one is the "),e.TgZ(124,"code"),e._uU(125,"compile()"),e.qZA(),e._uU(126," method. This method bootstraps a module with its dependencies (similar to the way an application is bootstrapped in the conventional "),e.TgZ(127,"code"),e._uU(128,"main.ts"),e.qZA(),e._uU(129," file using "),e.TgZ(130,"code"),e._uU(131,"NestFactory.create()"),e.qZA(),e._uU(132,"), and returns a module that is ready for testing."),e.qZA(),e.TgZ(133,"blockquote",14)(134,"strong"),e._uU(135,"Hint"),e.qZA(),e._uU(136," The "),e.TgZ(137,"code"),e._uU(138,"compile()"),e.qZA(),e._uU(139," method is "),e.TgZ(140,"strong"),e._uU(141,"asynchronous"),e.qZA(),e._uU(142," and therefore has to be awaited. Once the module is compiled you can retrieve any "),e.TgZ(143,"strong"),e._uU(144,"static"),e.qZA(),e._uU(145," instance it declares (controllers and providers) using the "),e.TgZ(146,"code"),e._uU(147,"get()"),e.qZA(),e._uU(148," method.\n"),e.qZA(),e.TgZ(149,"p")(150,"code"),e._uU(151,"TestingModule"),e.qZA(),e._uU(152," inherits from the "),e.TgZ(153,"a",17),e._uU(154,"module reference"),e.qZA(),e._uU(155," class, and therefore its ability to dynamically resolve scoped providers (transient or request-scoped). Do this with the "),e.TgZ(156,"code"),e._uU(157,"resolve()"),e.qZA(),e._uU(158," method (the "),e.TgZ(159,"code"),e._uU(160,"get()"),e.qZA(),e._uU(161," method can only retrieve static instances)."),e.qZA(),e.TgZ(162,"pre")(163,"code",13),e._uU(164,"\nconst moduleRef = await Test.createTestingModule({\n controllers: [CatsController],\n providers: [CatsService],\n}).compile();\n\ncatsService = await moduleRef.resolve(CatsService);\n"),e.qZA()(),e.TgZ(165,"blockquote",18)(166,"strong"),e._uU(167,"Warning"),e.qZA(),e._uU(168," The "),e.TgZ(169,"code"),e._uU(170,"resolve()"),e.qZA(),e._uU(171," method returns a unique instance of the provider, from its own "),e.TgZ(172,"strong"),e._uU(173,"DI container sub-tree"),e.qZA(),e._uU(174,". Each sub-tree has a unique context identifier. Thus, if you call this method more than once and compare instance references, you will see that they are not equal.\n"),e.qZA(),e.TgZ(175,"blockquote",14)(176,"strong"),e._uU(177,"Hint"),e.qZA(),e._uU(178," Learn more about the module reference features "),e.TgZ(179,"a",17),e._uU(180,"here"),e.qZA(),e._uU(181,".\n"),e.qZA(),e.TgZ(182,"p"),e._uU(183,"Instead of using the production version of any provider, you can override it with a "),e.TgZ(184,"a",19),e._uU(185,"custom provider"),e.qZA(),e._uU(186," for testing purposes. For example, you can mock a database service instead of connecting to a live database. We'll cover overrides in the next section, but they're available for unit tests as well."),e.qZA(),e.TgZ(187,"p"),e._UZ(188,"app-banner-courses"),e.qZA(),e.TgZ(189,"h4",20)(190,"span"),e._uU(191,"Auto mocking"),e.qZA()(),e.TgZ(192,"p"),e._uU(193,"Nest also allows you to define a mock factory to apply to all of your missing dependencies. This is useful for cases where you have a large number of dependencies in a class and mocking all of them will take a long time and a lot of setup. To make use of this feature, the "),e.TgZ(194,"code"),e._uU(195,"createTestingModule()"),e.qZA(),e._uU(196," will need to be chained up with the "),e.TgZ(197,"code"),e._uU(198,"useMocker()"),e.qZA(),e._uU(199," method, passing a factory for your dependency mocks. This factory can take in an optional token, which is an instance token, any token which is valid for a Nest provider, and returns a mock implementation. The below is an example of creating a generic mocker using "),e.TgZ(200,"a",21)(201,"code"),e._uU(202,"jest-mock"),e.qZA()(),e._uU(203," and a specific mock for "),e.TgZ(204,"code"),e._uU(205,"CatsService"),e.qZA(),e._uU(206," using "),e.TgZ(207,"code"),e._uU(208,"jest.fn()"),e.qZA(),e._uU(209,"."),e.qZA(),e.TgZ(210,"pre")(211,"code",13),e._uU(212,"\n// ...\nimport { ModuleMocker, MockFunctionMetadata } from 'jest-mock';\n\nconst moduleMocker = new ModuleMocker(global);\n\ndescribe('CatsController', () => {\n let controller: CatsController;\n\n beforeEach(async () => {\n const moduleRef = await Test.createTestingModule({\n controllers: [CatsController],\n })\n .useMocker((token) => {\n const results = ['test1', 'test2'];\n if (token === CatsService) {\n return { findAll: jest.fn().mockResolvedValue(results) };\n }\n if (typeof token === 'function') {\n const mockMetadata = moduleMocker.getMetadata(token) as MockFunctionMetadata<any, any>;\n const Mock = moduleMocker.generateFromMetadata(mockMetadata);\n return new Mock();\n }\n })\n .compile();\n\n controller = moduleRef.get(CatsController);\n });\n});\n"),e.qZA()(),e.TgZ(213,"p"),e._uU(214,"You can also retrieve these mocks out of the testing container as you normally would custom providers, "),e.TgZ(215,"code"),e._uU(216,"moduleRef.get(CatsService)"),e.qZA(),e._uU(217,"."),e.qZA(),e.TgZ(218,"blockquote",14)(219,"strong"),e._uU(220,"Hint"),e.qZA(),e._uU(221," A general mock factory, like "),e.TgZ(222,"code"),e._uU(223,"createMock"),e.qZA(),e._uU(224," from "),e.TgZ(225,"a",22)(226,"code"),e._uU(227,"@golevelup/ts-jest"),e.qZA()(),e._uU(228," can also be passed directly.\n"),e.qZA(),e.TgZ(229,"blockquote",14)(230,"strong"),e._uU(231,"Hint"),e.qZA(),e.TgZ(232,"code"),e._uU(233,"REQUEST"),e.qZA(),e._uU(234," and "),e.TgZ(235,"code"),e._uU(236,"INQUIRER"),e.qZA(),e._uU(237," providers cannot be auto-mocked because they're already pre-defined in the context. However, they can be "),e.TgZ(238,"em"),e._uU(239,"overwritten"),e.qZA(),e._uU(240," using the custom provider syntax or by utilizing the "),e.TgZ(241,"code"),e._uU(242,".overrideProvider"),e.qZA(),e._uU(243," method.\n"),e.qZA(),e.TgZ(244,"h4",23)(245,"span"),e._uU(246,"End-to-end testing"),e.qZA()(),e.TgZ(247,"p"),e._uU(248,"Unlike unit testing, which focuses on individual modules and classes, end-to-end (e2e) testing covers the interaction of classes and modules at a more aggregate level -- closer to the kind of interaction that end-users will have with the production system. As an application grows, it becomes hard to manually test the end-to-end behavior of each API endpoint. Automated end-to-end tests help us ensure that the overall behavior of the system is correct and meets project requirements. To perform e2e tests we use a similar configuration to the one we just covered in "),e.TgZ(249,"strong"),e._uU(250,"unit testing"),e.qZA(),e._uU(251,". In addition, Nest makes it easy to use the "),e.TgZ(252,"a",7),e._uU(253,"Supertest"),e.qZA(),e._uU(254," library to simulate HTTP requests."),e.qZA(),e.TgZ(255,"span",11),e._uU(256),e.ALo(257,"extension"),e._UZ(258,"app-tabs",null,24),e.qZA(),e.TgZ(260,"pre")(261,"code",13),e._uU(262,"\nimport * as request from 'supertest';\nimport { Test } from '@nestjs/testing';\nimport { CatsModule } from '../../src/cats/cats.module';\nimport { CatsService } from '../../src/cats/cats.service';\nimport { INestApplication } from '@nestjs/common';\n\ndescribe('Cats', () => {\n let app: INestApplication;\n let catsService = { findAll: () => ['test'] };\n\n beforeAll(async () => {\n const moduleRef = await Test.createTestingModule({\n imports: [CatsModule],\n })\n .overrideProvider(CatsService)\n .useValue(catsService)\n .compile();\n\n app = moduleRef.createNestApplication();\n await app.init();\n });\n\n it(`/GET cats`, () => {\n return request(app.getHttpServer())\n .get('/cats')\n .expect(200)\n .expect({\n data: catsService.findAll(),\n });\n });\n\n afterAll(async () => {\n await app.close();\n });\n});\n"),e.qZA()(),e.TgZ(263,"pre")(264,"code",13),e._uU(265,"\nimport * as request from 'supertest';\nimport { Test } from '@nestjs/testing';\nimport { CatsModule } from '../../src/cats/cats.module';\nimport { CatsService } from '../../src/cats/cats.service';\nimport { INestApplication } from '@nestjs/common';\n\ndescribe('Cats', () => {\n let app: INestApplication;\n let catsService = { findAll: () => ['test'] };\n\n beforeAll(async () => {\n const moduleRef = await Test.createTestingModule({\n imports: [CatsModule],\n })\n .overrideProvider(CatsService)\n .useValue(catsService)\n .compile();\n\n app = moduleRef.createNestApplication();\n await app.init();\n });\n\n it(`/GET cats`, () => {\n return request(app.getHttpServer())\n .get('/cats')\n .expect(200)\n .expect({\n data: catsService.findAll(),\n });\n });\n\n afterAll(async () => {\n await app.close();\n });\n});\n"),e.qZA()(),e.TgZ(266,"blockquote",14)(267,"strong"),e._uU(268,"Hint"),e.qZA(),e._uU(269," If you're using "),e.TgZ(270,"a",25),e._uU(271,"Fastify"),e.qZA(),e._uU(272," as your HTTP adapter, it requires a slightly different configuration, and has built-in testing capabilities:\n"),e.TgZ(273,"pre")(274,"code",26),e._uU(275,"\nlet app: NestFastifyApplication;\n\nbeforeAll(async () => {\n app = moduleRef.createNestApplication<NestFastifyApplication>(new FastifyAdapter());\n\n await app.init();\n await app.getHttpAdapter().getInstance().ready();\n});\n\nit(`/GET cats`, () => {\n return app\n .inject({\n method: 'GET',\n url: '/cats',\n })\n .then((result) => {\n expect(result.statusCode).toEqual(200);\n expect(result.payload).toEqual(/* expectedPayload */);\n });\n});\n\nafterAll(async () => {\n await app.close();\n});\n"),e.qZA()()(),e.TgZ(276,"p"),e._uU(277,"In this example, we build on some of the concepts described earlier. In addition to the "),e.TgZ(278,"code"),e._uU(279,"compile()"),e.qZA(),e._uU(280," method we used earlier, we now use the "),e.TgZ(281,"code"),e._uU(282,"createNestApplication()"),e.qZA(),e._uU(283," method to instantiate a full Nest runtime environment. We save a reference to the running app in our "),e.TgZ(284,"code"),e._uU(285,"app"),e.qZA(),e._uU(286," variable so we can use it to simulate HTTP requests."),e.qZA(),e.TgZ(287,"p"),e._uU(288,"We simulate HTTP tests using the "),e.TgZ(289,"code"),e._uU(290,"request()"),e.qZA(),e._uU(291," function from Supertest. We want these HTTP requests to route to our running Nest app, so we pass the "),e.TgZ(292,"code"),e._uU(293,"request()"),e.qZA(),e._uU(294," function a reference to the HTTP listener that underlies Nest (which, in turn, may be provided by the Express platform). Hence the construction "),e.TgZ(295,"code"),e._uU(296,"request(app.getHttpServer())"),e.qZA(),e._uU(297,". The call to "),e.TgZ(298,"code"),e._uU(299,"request()"),e.qZA(),e._uU(300," hands us a wrapped HTTP Server, now connected to the Nest app, which exposes methods to simulate an actual HTTP request. For example, using "),e.TgZ(301,"code"),e._uU(302,"request(...).get('/cats')"),e.qZA(),e._uU(303," will initiate a request to the Nest app that is identical to an "),e.TgZ(304,"strong"),e._uU(305,"actual"),e.qZA(),e._uU(306," HTTP request like "),e.TgZ(307,"code"),e._uU(308,"get '/cats'"),e.qZA(),e._uU(309," coming in over the network."),e.qZA(),e.TgZ(310,"p"),e._uU(311,"In this example, we also provide an alternate (test-double) implementation of the "),e.TgZ(312,"code"),e._uU(313,"CatsService"),e.qZA(),e._uU(314," which simply returns a hard-coded value that we can test for. Use "),e.TgZ(315,"code"),e._uU(316,"overrideProvider()"),e.qZA(),e._uU(317," to provide such an alternate implementation. Similarly, Nest provides methods to override modules, guards, interceptors, filters and pipes with the "),e.TgZ(318,"code"),e._uU(319,"overrideModule()"),e.qZA(),e._uU(320,", "),e.TgZ(321,"code"),e._uU(322,"overrideGuard()"),e.qZA(),e._uU(323,", "),e.TgZ(324,"code"),e._uU(325,"overrideInterceptor()"),e.qZA(),e._uU(326,", "),e.TgZ(327,"code"),e._uU(328,"overrideFilter()"),e.qZA(),e._uU(329,", and "),e.TgZ(330,"code"),e._uU(331,"overridePipe()"),e.qZA(),e._uU(332," methods respectively."),e.qZA(),e.TgZ(333,"p"),e._uU(334,"Each of the override methods (except for "),e.TgZ(335,"code"),e._uU(336,"overrideModule()"),e.qZA(),e._uU(337,") returns an object with 3 different methods that mirror those described for "),e.TgZ(338,"a",27),e._uU(339,"custom providers"),e.qZA(),e._uU(340,":"),e.qZA(),e.TgZ(341,"ul")(342,"li")(343,"code"),e._uU(344,"useClass"),e.qZA(),e._uU(345,": you supply a class that will be instantiated to provide the instance to override the object (provider, guard, etc.)."),e.qZA(),e.TgZ(346,"li")(347,"code"),e._uU(348,"useValue"),e.qZA(),e._uU(349,": you supply an instance that will override the object."),e.qZA(),e.TgZ(350,"li")(351,"code"),e._uU(352,"useFactory"),e.qZA(),e._uU(353,": you supply a function that returns an instance that will override the object."),e.qZA()(),e.TgZ(354,"p"),e._uU(355,"On the other hand, "),e.TgZ(356,"code"),e._uU(357,"overrideModule()"),e.qZA(),e._uU(358," returns an object with the "),e.TgZ(359,"code"),e._uU(360,"useModule()"),e.qZA(),e._uU(361," method, which you can use to supply a module that will override the original module, as follows:"),e.qZA(),e.TgZ(362,"pre")(363,"code",13),e._uU(364,"\nconst moduleRef = await Test.createTestingModule({\n imports: [AppModule],\n})\n .overrideModule(CatsModule)\n .useModule(AlternateCatsModule)\n .compile();\n"),e.qZA()(),e.TgZ(365,"p"),e._uU(366,"Each of the override method types, in turn, returns the "),e.TgZ(367,"code"),e._uU(368,"TestingModule"),e.qZA(),e._uU(369," instance, and can thus be chained with other methods in the "),e.TgZ(370,"a",28),e._uU(371,"fluent style"),e.qZA(),e._uU(372,". You should use "),e.TgZ(373,"code"),e._uU(374,"compile()"),e.qZA(),e._uU(375," at the end of such a chain to cause Nest to instantiate and initialize the module."),e.qZA(),e.TgZ(376,"p"),e._uU(377,"Also, sometimes you may want to provide a custom logger e.g. when the tests are run (for example, on a CI server). Use the "),e.TgZ(378,"code"),e._uU(379,"setLogger()"),e.qZA(),e._uU(380," method and pass an object that fulfills the "),e.TgZ(381,"code"),e._uU(382,"LoggerService"),e.qZA(),e._uU(383," interface to instruct the "),e.TgZ(384,"code"),e._uU(385,"TestModuleBuilder"),e.qZA(),e._uU(386,' how to log during tests (by default, only "error" logs will be logged to the console).'),e.qZA(),e.TgZ(387,"blockquote",18)(388,"strong"),e._uU(389,"Warning"),e.qZA(),e._uU(390," The "),e.TgZ(391,"code"),e._uU(392,"@nestjs/core"),e.qZA(),e._uU(393," package exposes unique provider tokens with the "),e.TgZ(394,"code"),e._uU(395,"APP_"),e.qZA(),e._uU(396," prefix to help on define global enhancers. Those tokens cannot be overridden since they can represent multiple providers. Thus you can't use "),e.TgZ(397,"code"),e._uU(398,".overrideProvider(APP_GUARD)"),e.qZA(),e._uU(399," (and so on). If you want to override some global enhancer, follow "),e.TgZ(400,"a",29),e._uU(401,"this workaround"),e.qZA(),e._uU(402,".\n"),e.qZA(),e.TgZ(403,"p"),e._uU(404,"The compiled module has several useful methods, as described in the following table:"),e.qZA(),e.TgZ(405,"table")(406,"tr")(407,"td")(408,"code"),e._uU(409,"createNestApplication()"),e.qZA()(),e.TgZ(410,"td"),e._uU(411," Creates and returns a Nest application ("),e.TgZ(412,"code"),e._uU(413,"INestApplication"),e.qZA(),e._uU(414," instance) based on the given module. Note that you must manually initialize the application using the "),e.TgZ(415,"code"),e._uU(416,"init()"),e.qZA(),e._uU(417," method. "),e.qZA()(),e.TgZ(418,"tr")(419,"td")(420,"code"),e._uU(421,"createNestMicroservice()"),e.qZA()(),e.TgZ(422,"td"),e._uU(423," Creates and returns a Nest microservice ("),e.TgZ(424,"code"),e._uU(425,"INestMicroservice"),e.qZA(),e._uU(426," instance) based on the given module. "),e.qZA()(),e.TgZ(427,"tr")(428,"td")(429,"code"),e._uU(430,"get()"),e.qZA()(),e.TgZ(431,"td"),e._uU(432," Retrieves a static instance of a controller or provider (including guards, filters, etc.) available in the application context. Inherited from the "),e.TgZ(433,"a",30),e._uU(434,"module reference"),e.qZA(),e._uU(435," class. "),e.qZA()(),e.TgZ(436,"tr")(437,"td")(438,"code"),e._uU(439,"resolve()"),e.qZA()(),e.TgZ(440,"td"),e._uU(441," Retrieves a dynamically created scoped instance (request or transient) of a controller or provider (including guards, filters, etc.) available in the application context. Inherited from the "),e.TgZ(442,"a",30),e._uU(443,"module reference"),e.qZA(),e._uU(444," class. "),e.qZA()(),e.TgZ(445,"tr")(446,"td")(447,"code"),e._uU(448,"select()"),e.qZA()(),e.TgZ(449,"td"),e._uU(450," Navigates through the module's dependency graph; can be used to retrieve a specific instance from the selected module (used along with strict mode ("),e.TgZ(451,"code"),e._uU(452,"strict: true"),e.qZA(),e._uU(453,") in "),e.TgZ(454,"code"),e._uU(455,"get()"),e.qZA(),e._uU(456," method). "),e.qZA()()(),e.TgZ(457,"blockquote",14)(458,"strong"),e._uU(459,"Hint"),e.qZA(),e._uU(460," Keep your e2e test files inside the "),e.TgZ(461,"code"),e._uU(462,"test"),e.qZA(),e._uU(463," directory. The testing files should have a "),e.TgZ(464,"code"),e._uU(465,".e2e-spec"),e.qZA(),e._uU(466," suffix.\n"),e.qZA(),e.TgZ(467,"h4",31)(468,"span"),e._uU(469,"Overriding globally registered enhancers"),e.qZA()(),e.TgZ(470,"p"),e._uU(471,"If you have a globally registered guard (or pipe, interceptor, or filter), you need to take a few more steps to override that enhancer. To recap the original registration looks like this:"),e.qZA(),e.TgZ(472,"pre")(473,"code",13),e._uU(474,"\nproviders: [\n {\n provide: APP_GUARD,\n useClass: JwtAuthGuard,\n },\n],\n"),e.qZA()(),e.TgZ(475,"p"),e._uU(476,'This is registering the guard as a "multi"-provider through the '),e.TgZ(477,"code"),e._uU(478,"APP_*"),e.qZA(),e._uU(479," token. To be able to replace the "),e.TgZ(480,"code"),e._uU(481,"JwtAuthGuard"),e.qZA(),e._uU(482," here, the registration needs to use an existing provider in this slot:"),e.qZA(),e.TgZ(483,"pre")(484,"code",13),e._uU(485,"\nproviders: [\n {\n provide: APP_GUARD,\n useExisting: JwtAuthGuard,\n // ^^^^^^^^ notice the use of 'useExisting' instead of 'useClass'\n },\n JwtAuthGuard,\n],\n"),e.qZA()(),e.TgZ(486,"blockquote",14)(487,"strong"),e._uU(488,"Hint"),e.qZA(),e._uU(489," Change the "),e.TgZ(490,"code"),e._uU(491,"useClass"),e.qZA(),e._uU(492," to "),e.TgZ(493,"code"),e._uU(494,"useExisting"),e.qZA(),e._uU(495," to reference a registered provider instead of having Nest instantiate it behind the token.\n"),e.qZA(),e.TgZ(496,"p"),e._uU(497,"Now the "),e.TgZ(498,"code"),e._uU(499,"JwtAuthGuard"),e.qZA(),e._uU(500," is visible to Nest as a regular provider that can be overridden when creating the "),e.TgZ(501,"code"),e._uU(502,"TestingModule"),e.qZA(),e._uU(503,":"),e.qZA(),e.TgZ(504,"pre")(505,"code",13),e._uU(506,"\nconst moduleRef = await Test.createTestingModule({\n imports: [AppModule],\n})\n .overrideProvider(JwtAuthGuard)\n .useClass(MockAuthGuard)\n .compile();\n"),e.qZA()(),e.TgZ(507,"p"),e._uU(508,"Now all your tests will use the "),e.TgZ(509,"code"),e._uU(510,"MockAuthGuard"),e.qZA(),e._uU(511," on every request."),e.qZA(),e.TgZ(512,"h4",32)(513,"span"),e._uU(514,"Testing request-scoped instances"),e.qZA()(),e.TgZ(515,"p")(516,"a",33),e._uU(517,"Request-scoped"),e.qZA(),e._uU(518," providers are created uniquely for each incoming "),e.TgZ(519,"strong"),e._uU(520,"request"),e.qZA(),e._uU(521,". The instance is garbage-collected after the request has completed processing. This poses a problem, because we can't access a dependency injection sub-tree generated specifically for a tested request."),e.qZA(),e.TgZ(522,"p"),e._uU(523,"We know (based on the sections above) that the "),e.TgZ(524,"code"),e._uU(525,"resolve()"),e.qZA(),e._uU(526," method can be used to retrieve a dynamically instantiated class. Also, as described "),e.TgZ(527,"a",34),e._uU(528,"here"),e.qZA(),e._uU(529,", we know we can pass a unique context identifier to control the lifecycle of a DI container sub-tree. How do we leverage this in a testing context?"),e.qZA(),e.TgZ(530,"p"),e._uU(531,"The strategy is to generate a context identifier beforehand and force Nest to use this particular ID to create a sub-tree for all incoming requests. In this way we'll be able to retrieve instances created for a tested request."),e.qZA(),e.TgZ(532,"p"),e._uU(533,"To accomplish this, use "),e.TgZ(534,"code"),e._uU(535,"jest.spyOn()"),e.qZA(),e._uU(536," on the "),e.TgZ(537,"code"),e._uU(538,"ContextIdFactory"),e.qZA(),e._uU(539,":"),e.qZA(),e.TgZ(540,"pre")(541,"code",13),e._uU(542,"\nconst contextId = ContextIdFactory.create();\njest.spyOn(ContextIdFactory, 'getByRequest').mockImplementation(() => contextId);\n"),e.qZA()(),e.TgZ(543,"p"),e._uU(544,"Now we can use the "),e.TgZ(545,"code"),e._uU(546,"contextId"),e.qZA(),e._uU(547," to access a single generated DI container sub-tree for any subsequent request."),e.qZA(),e.TgZ(548,"pre")(549,"code",13),e._uU(550,"\ncatsService = await moduleRef.resolve(CatsService, contextId);\n"),e.qZA()()()),2&n){const a=e.MAs(57),r=e.MAs(100),i=e.MAs(259);e.xp6(54),e.hij(" ",e.xi3(55,15,"cats.controller.spec",a.isJsActive),"\n"),e.xp6(4),e.ekj("hide",a.isJsActive),e.xp6(3),e.ekj("hide",!a.isJsActive),e.xp6(36),e.hij(" ",e.xi3(98,18,"cats.controller.spec",r.isJsActive),"\n"),e.xp6(4),e.ekj("hide",r.isJsActive),e.xp6(3),e.ekj("hide",!r.isJsActive),e.xp6(152),e.hij(" ",e.xi3(257,21,"cats.e2e-spec",i.isJsActive),"\n"),e.xp6(4),e.ekj("hide",i.isJsActive),e.xp6(3),e.ekj("hide",!i.isJsActive)}},dependencies:[h.n,l.U,m.f,p.rH,U.F],encapsulation:2,changeDetection:0})}return t})(),data:{title:"Testing"}},{path:"injection-scopes",component:(()=>{class t extends d.y{static \u0275fac=function(){let o;return function(s){return(o||(o=e.n5z(t)))(s||t)}}();static \u0275cmp=e.Xpm({type:t,selectors:[["app-provider-scopes"]],features:[e.qOj],decls:382,vars:0,consts:[[1,"content"],["contentReference",""],[1,"github-links"],["href","https://github.com/ChuTingzj/docs.nestjs.zh-cn.com/tree/master/content/fundamentals/provider-scopes.md","aria-label","Suggest Edits","title","Suggest Edits"],[1,"fas","fa-edit"],["id","injection-scopes"],["appAnchor","","id","provider-scope"],[1,"info"],["appAnchor","","id","usage"],[1,"language-typescript"],["routerLink","/fundamentals/custom-providers"],[1,"warning"],["href","../security/authentication#request-scoped-strategies"],["appAnchor","","id","controller-scope"],["appAnchor","","id","scope-hierarchy"],["appAnchor","","id","request-provider"],["routerLink","/graphql/quick-start"],["appAnchor","","id","inquirer-provider"],["appAnchor","","id","performance"],["appAnchor","","id","durable-providers"],["href","/fundamentals/module-ref#resolving-scoped-providers"]],template:function(n,s){1&n&&(e.TgZ(0,"div",0,1)(2,"div",2)(3,"a",3),e._UZ(4,"i",4),e.qZA()(),e.TgZ(5,"h3",5),e._uU(6,"Injection scopes"),e.qZA(),e.TgZ(7,"p"),e._uU(8,"For people coming from different programming language backgrounds, it might be unexpected to learn that in Nest, almost everything is shared across incoming requests. We have a connection pool to the database, singleton services with global state, etc. Remember that Node.js doesn't follow the request/response Multi-Threaded Stateless Model in which every request is processed by a separate thread. Hence, using singleton instances is fully "),e.TgZ(9,"strong"),e._uU(10,"safe"),e.qZA(),e._uU(11," for our applications."),e.qZA(),e.TgZ(12,"p"),e._uU(13,"However, there are edge-cases when request-based lifetime may be the desired behavior, for instance per-request caching in GraphQL applications, request tracking, and multi-tenancy. Injection scopes provide a mechanism to obtain the desired provider lifetime behavior."),e.qZA(),e.TgZ(14,"h4",6)(15,"span"),e._uU(16,"Provider scope"),e.qZA()(),e.TgZ(17,"p"),e._uU(18,"A provider can have any of the following scopes:"),e.qZA(),e.TgZ(19,"table")(20,"tr")(21,"td")(22,"code"),e._uU(23,"DEFAULT"),e.qZA()(),e.TgZ(24,"td"),e._uU(25,"A single instance of the provider is shared across the entire application. The instance lifetime is tied directly to the application lifecycle. Once the application has bootstrapped, all singleton providers have been instantiated. Singleton scope is used by default."),e.qZA()(),e.TgZ(26,"tr")(27,"td")(28,"code"),e._uU(29,"REQUEST"),e.qZA()(),e.TgZ(30,"td"),e._uU(31,"A new instance of the provider is created exclusively for each incoming "),e.TgZ(32,"strong"),e._uU(33,"request"),e.qZA(),e._uU(34,". The instance is garbage-collected after the request has completed processing."),e.qZA()(),e.TgZ(35,"tr")(36,"td")(37,"code"),e._uU(38,"TRANSIENT"),e.qZA()(),e.TgZ(39,"td"),e._uU(40,"Transient providers are not shared across consumers. Each consumer that injects a transient provider will receive a new, dedicated instance."),e.qZA()()(),e.TgZ(41,"blockquote",7)(42,"strong"),e._uU(43,"Hint"),e.qZA(),e._uU(44," Using singleton scope is "),e.TgZ(45,"strong"),e._uU(46,"recommended"),e.qZA(),e._uU(47," for most use cases. Sharing providers across consumers and across requests means that an instance can be cached and its initialization occurs only once, during application startup.\n"),e.qZA(),e.TgZ(48,"h4",8)(49,"span"),e._uU(50,"Usage"),e.qZA()(),e.TgZ(51,"p"),e._uU(52,"Specify injection scope by passing the "),e.TgZ(53,"code"),e._uU(54,"scope"),e.qZA(),e._uU(55," property to the "),e.TgZ(56,"code"),e._uU(57,"@Injectable()"),e.qZA(),e._uU(58," decorator options object:"),e.qZA(),e.TgZ(59,"pre")(60,"code",9),e._uU(61,"\nimport { Injectable, Scope } from '@nestjs/common';\n\n@Injectable({ scope: Scope.REQUEST })\nexport class CatsService {}\n"),e.qZA()(),e.TgZ(62,"p"),e._uU(63,"Similarly, for "),e.TgZ(64,"a",10),e._uU(65,"custom providers"),e.qZA(),e._uU(66,", set the "),e.TgZ(67,"code"),e._uU(68,"scope"),e.qZA(),e._uU(69," property in the long-hand form for a provider registration:"),e.qZA(),e.TgZ(70,"pre")(71,"code",9),e._uU(72,"\n{\n provide: 'CACHE_MANAGER',\n useClass: CacheManager,\n scope: Scope.TRANSIENT,\n}\n"),e.qZA()(),e.TgZ(73,"blockquote",7)(74,"strong"),e._uU(75,"Hint"),e.qZA(),e._uU(76," Import the "),e.TgZ(77,"code"),e._uU(78,"Scope"),e.qZA(),e._uU(79," enum from "),e.TgZ(80,"code"),e._uU(81,"@nestjs/common"),e.qZA()(),e.TgZ(82,"p"),e._uU(83,"Singleton scope is used by default, and need not be declared. If you do want to declare a provider as singleton scoped, use the "),e.TgZ(84,"code"),e._uU(85,"Scope.DEFAULT"),e.qZA(),e._uU(86," value for the "),e.TgZ(87,"code"),e._uU(88,"scope"),e.qZA(),e._uU(89," property."),e.qZA(),e.TgZ(90,"blockquote",11)(91,"strong"),e._uU(92,"Notice"),e.qZA(),e._uU(93," Websocket Gateways should not use request-scoped providers because they must act as singletons. Each gateway encapsulates a real socket and cannot be instantiated multiple times. The limitation also applies to some other providers, like "),e.TgZ(94,"a",12)(95,"em"),e._uU(96,"Passport strategies"),e.qZA()(),e._uU(97," or "),e.TgZ(98,"em"),e._uU(99,"Cron controllers"),e.qZA(),e._uU(100,".\n"),e.qZA(),e.TgZ(101,"h4",13)(102,"span"),e._uU(103,"Controller scope"),e.qZA()(),e.TgZ(104,"p"),e._uU(105,"Controllers can also have scope, which applies to all request method handlers declared in that controller. Like provider scope, the scope of a controller declares its lifetime. For a request-scoped controller, a new instance is created for each inbound request, and garbage-collected when the request has completed processing."),e.qZA(),e.TgZ(106,"p"),e._uU(107,"Declare controller scope with the "),e.TgZ(108,"code"),e._uU(109,"scope"),e.qZA(),e._uU(110," property of the "),e.TgZ(111,"code"),e._uU(112,"ControllerOptions"),e.qZA(),e._uU(113," object:"),e.qZA(),e.TgZ(114,"pre")(115,"code",9),e._uU(116,"\n@Controller({\n path: 'cats',\n scope: Scope.REQUEST,\n})\nexport class CatsController {}\n"),e.qZA()(),e.TgZ(117,"h4",14)(118,"span"),e._uU(119,"Scope hierarchy"),e.qZA()(),e.TgZ(120,"p"),e._uU(121,"The "),e.TgZ(122,"code"),e._uU(123,"REQUEST"),e.qZA(),e._uU(124," scope bubbles up the injection chain. A controller that depends on a request-scoped provider will, itself, be request-scoped."),e.qZA(),e.TgZ(125,"p"),e._uU(126,"Imagine the following dependency graph: "),e.TgZ(127,"code"),e._uU(128,"CatsController <- CatsService <- CatsRepository"),e.qZA(),e._uU(129,". If "),e.TgZ(130,"code"),e._uU(131,"CatsService"),e.qZA(),e._uU(132," is request-scoped (and the others are default singletons), the "),e.TgZ(133,"code"),e._uU(134,"CatsController"),e.qZA(),e._uU(135," will become request-scoped as it is dependent on the injected service. The "),e.TgZ(136,"code"),e._uU(137,"CatsRepository"),e.qZA(),e._uU(138,", which is not dependent, would remain singleton-scoped."),e.qZA(),e.TgZ(139,"p"),e._uU(140,"Transient-scoped dependencies don't follow that pattern. If a singleton-scoped "),e.TgZ(141,"code"),e._uU(142,"DogsService"),e.qZA(),e._uU(143," injects a transient "),e.TgZ(144,"code"),e._uU(145,"LoggerService"),e.qZA(),e._uU(146," provider, it will receive a fresh instance of it. However, "),e.TgZ(147,"code"),e._uU(148,"DogsService"),e.qZA(),e._uU(149," will stay singleton-scoped, so injecting it anywhere would "),e.TgZ(150,"em"),e._uU(151,"not"),e.qZA(),e._uU(152," resolve to a new instance of "),e.TgZ(153,"code"),e._uU(154,"DogsService"),e.qZA(),e._uU(155,". In case it's desired behavior, "),e.TgZ(156,"code"),e._uU(157,"DogsService"),e.qZA(),e._uU(158," must be explicitly marked as "),e.TgZ(159,"code"),e._uU(160,"TRANSIENT"),e.qZA(),e._uU(161," as well."),e.qZA(),e.TgZ(162,"p"),e._UZ(163,"app-banner-courses"),e.qZA(),e.TgZ(164,"h4",15)(165,"span"),e._uU(166,"Request provider"),e.qZA()(),e.TgZ(167,"p"),e._uU(168,"In an HTTP server-based application (e.g., using "),e.TgZ(169,"code"),e._uU(170,"@nestjs/platform-express"),e.qZA(),e._uU(171," or "),e.TgZ(172,"code"),e._uU(173,"@nestjs/platform-fastify"),e.qZA(),e._uU(174,"), you may want to access a reference to the original request object when using request-scoped providers. You can do this by injecting the "),e.TgZ(175,"code"),e._uU(176,"REQUEST"),e.qZA(),e._uU(177," object."),e.qZA(),e.TgZ(178,"pre")(179,"code",9),e._uU(180,"\nimport { Injectable, Scope, Inject } from '@nestjs/common';\nimport { REQUEST } from '@nestjs/core';\nimport { Request } from 'express';\n\n@Injectable({ scope: Scope.REQUEST })\nexport class CatsService {\n constructor(@Inject(REQUEST) private request: Request) {}\n}\n"),e.qZA()(),e.TgZ(181,"p"),e._uU(182,"Because of underlying platform/protocol differences, you access the inbound request slightly differently for Microservice or GraphQL applications. In "),e.TgZ(183,"a",16),e._uU(184,"GraphQL"),e.qZA(),e._uU(185," applications, you inject "),e.TgZ(186,"code"),e._uU(187,"CONTEXT"),e.qZA(),e._uU(188," instead of "),e.TgZ(189,"code"),e._uU(190,"REQUEST"),e.qZA(),e._uU(191,":"),e.qZA(),e.TgZ(192,"pre")(193,"code",9),e._uU(194,"\nimport { Injectable, Scope, Inject } from '@nestjs/common';\nimport { CONTEXT } from '@nestjs/graphql';\n\n@Injectable({ scope: Scope.REQUEST })\nexport class CatsService {\n constructor(@Inject(CONTEXT) private context) {}\n}\n"),e.qZA()(),e.TgZ(195,"p"),e._uU(196,"You then configure your "),e.TgZ(197,"code"),e._uU(198,"context"),e.qZA(),e._uU(199," value (in the "),e.TgZ(200,"code"),e._uU(201,"GraphQLModule"),e.qZA(),e._uU(202,") to contain "),e.TgZ(203,"code"),e._uU(204,"request"),e.qZA(),e._uU(205," as its property."),e.qZA(),e.TgZ(206,"h4",17)(207,"span"),e._uU(208,"Inquirer provider"),e.qZA()(),e.TgZ(209,"p"),e._uU(210,"If you want to get the class where a provider was constructed, for instance in logging or metrics providers, you can inject the "),e.TgZ(211,"code"),e._uU(212,"INQUIRER"),e.qZA(),e._uU(213," token."),e.qZA(),e.TgZ(214,"pre")(215,"code",9),e._uU(216,"\nimport { Inject, Injectable, Scope } from '@nestjs/common';\nimport { INQUIRER } from '@nestjs/core';\n\n@Injectable({ scope: Scope.TRANSIENT })\nexport class HelloService {\n constructor(@Inject(INQUIRER) private parentClass: object) {}\n\n sayHello(message: string) {\n console.log(`${this.parentClass?.constructor?.name}: ${message}`);\n }\n}\n"),e.qZA()(),e.TgZ(217,"p"),e._uU(218,"And then use it as follows:"),e.qZA(),e.TgZ(219,"pre")(220,"code",9),e._uU(221,"\nimport { Injectable } from '@nestjs/common';\nimport { HelloService } from './hello.service';\n\n@Injectable()\nexport class AppService {\n constructor(private helloService: HelloService) {}\n\n getRoot(): string {\n this.helloService.sayHello('My name is getRoot');\n\n return 'Hello world!';\n }\n}\n"),e.qZA()(),e.TgZ(222,"p"),e._uU(223,"In the example above when "),e.TgZ(224,"code"),e._uU(225,"AppService#getRoot"),e.qZA(),e._uU(226," is called, "),e.TgZ(227,"code"),e._uU(228,'"AppService: My name is getRoot"'),e.qZA(),e._uU(229," will be logged to the console."),e.qZA(),e.TgZ(230,"h4",18)(231,"span"),e._uU(232,"Performance"),e.qZA()(),e.TgZ(233,"p"),e._uU(234,"Using request-scoped providers will have an impact on application performance. While Nest tries to cache as much metadata as possible, it will still have to create an instance of your class on each request. Hence, it will slow down your average response time and overall benchmarking result. Unless a provider must be request-scoped, it is strongly recommended that you use the default singleton scope."),e.qZA(),e.TgZ(235,"blockquote",7)(236,"strong"),e._uU(237,"Hint"),e.qZA(),e._uU(238," Although it all sounds quite intimidating, a properly designed application that leverages request-scoped providers should not slow down by more than ~5% latency-wise.\n"),e.qZA(),e.TgZ(239,"h4",19)(240,"span"),e._uU(241,"Durable providers"),e.qZA()(),e.TgZ(242,"p"),e._uU(243,"Request-scoped providers, as mentioned in the section above, may lead to increased latency since having at least 1 request-scoped provider (injected into the controller instance, or deeper - injected into one of its providers) makes the controller request-scoped as well. That means, it must be recreated (instantiated) per each individual request (and garbage collected afterwards). Now, that also means, that for let's say 30k requests in parallel, there will be 30k ephemeral instances of the controller (and its request-scoped providers)."),e.qZA(),e.TgZ(244,"p"),e._uU(245,"Having a common provider that most providers depend on (think of a database connection, or a logger service), automatically converts all those providers to request-scoped providers as well. This can pose a challenge in "),e.TgZ(246,"strong"),e._uU(247,"multi-tenant applications"),e.qZA(),e._uU(248,', especially for those that have a central request-scoped "data source" provider that grabs headers/token from the request object and based on its values, retrieves the corresponding database connection/schema (specific to that tenant).'),e.qZA(),e.TgZ(249,"p"),e._uU(250,"For instance, let's say you have an application alternately used by 10 different customers. Each customer has its "),e.TgZ(251,"strong"),e._uU(252,"own dedicated data source"),e.qZA(),e._uU(253,', and you want to make sure customer A will never be able to reach customer B\'s database. One way to achieve this could be to declare a request-scoped "data source" provider that - based on the request object - determines what\'s the "current customer" and retrieves its corresponding database. With this approach, you can turn your application into a multi-tenant application in just a few minutes. But, a major downside to this approach is that since most likely a large chunk of your application\' components rely on the "data source" provider, they will implicitly become "request-scoped", and therefore you will undoubtedly see an impact in your apps performance.'),e.qZA(),e.TgZ(254,"p"),e._uU(255,"But what if we had a better solution? Since we only have 10 customers, couldn't we have 10 individual "),e.TgZ(256,"a",20),e._uU(257,"DI sub-trees"),e.qZA(),e._uU(258," per customer (instead of recreating each tree per request)? If your providers don't rely on any property that's truly unique for each consecutive request (e.g., request UUID) but instead there're some specific attributes that let us aggregate (classify) them, there's no reason to "),e.TgZ(259,"em"),e._uU(260,"recreate DI sub-tree"),e.qZA(),e._uU(261," on every incoming request."),e.qZA(),e.TgZ(262,"p"),e._uU(263,"And that's exactly when the "),e.TgZ(264,"strong"),e._uU(265,"durable providers"),e.qZA(),e._uU(266," come in handy."),e.qZA(),e.TgZ(267,"p"),e._uU(268,"Before we start flagging providers as durable, we must first register a "),e.TgZ(269,"strong"),e._uU(270,"strategy"),e.qZA(),e._uU(271,' that instructs Nest what are those "common request attributes", provide logic that groups requests - associates them with their corresponding DI sub-trees.'),e.qZA(),e.TgZ(272,"pre")(273,"code",9),e._uU(274,"\nimport {\n HostComponentInfo,\n ContextId,\n ContextIdFactory,\n ContextIdStrategy,\n} from '@nestjs/core';\nimport { Request } from 'express';\n\nconst tenants = new Map<string, ContextId>();\n\nexport class AggregateByTenantContextIdStrategy implements ContextIdStrategy {\n attach(contextId: ContextId, request: Request) {\n const tenantId = request.headers['x-tenant-id'] as string;\n let tenantSubTreeId: ContextId;\n\n if (tenants.has(tenantId)) {\n tenantSubTreeId = tenants.get(tenantId);\n } else {\n tenantSubTreeId = ContextIdFactory.create();\n tenants.set(tenantId, tenantSubTreeId);\n }\n\n // If tree is not durable, return the original \"contextId\" object\n return (info: HostComponentInfo) =>\n info.isTreeDurable ? tenantSubTreeId : contextId;\n }\n}\n"),e.qZA()(),e.TgZ(275,"blockquote",7)(276,"strong"),e._uU(277,"Hint"),e.qZA(),e._uU(278," Similar to the request scope, durability bubbles up the injection chain. That means if A depends on B which is flagged as "),e.TgZ(279,"code"),e._uU(280,"durable"),e.qZA(),e._uU(281,", A implicitly becomes durable too (unless "),e.TgZ(282,"code"),e._uU(283,"durable"),e.qZA(),e._uU(284," is explicitly set to "),e.TgZ(285,"code"),e._uU(286,"false"),e.qZA(),e._uU(287," for A provider).\n"),e.qZA(),e.TgZ(288,"blockquote",11)(289,"strong"),e._uU(290,"Warning"),e.qZA(),e._uU(291," Note this strategy is not ideal for applications operating with a large number of tenants.\n"),e.qZA(),e.TgZ(292,"p"),e._uU(293,"The value returned from the "),e.TgZ(294,"code"),e._uU(295,"attach"),e.qZA(),e._uU(296," method instructs Nest what context identifier should be used for a given host. In this case, we specified that the "),e.TgZ(297,"code"),e._uU(298,"tenantSubTreeId"),e.qZA(),e._uU(299," should be used instead of the original, auto-generated "),e.TgZ(300,"code"),e._uU(301,"contextId"),e.qZA(),e._uU(302," object, when the host component (e.g., request-scoped controller) is flagged as durable (you can learn how to mark providers as durable below). Also, in the above example, "),e.TgZ(303,"strong"),e._uU(304,"no payload"),e.qZA(),e._uU(305," would be registered (where payload = "),e.TgZ(306,"code"),e._uU(307,"REQUEST"),e.qZA(),e._uU(308,"/"),e.TgZ(309,"code"),e._uU(310,"CONTEXT"),e.qZA(),e._uU(311,' provider that represents the "root" - parent of the sub-tree).'),e.qZA(),e.TgZ(312,"p"),e._uU(313,"If you want to register the payload for a durable tree, use the following construction instead:"),e.qZA(),e.TgZ(314,"pre")(315,"code",9),e._uU(316,"\n// The return of `AggregateByTenantContextIdStrategy#attach` method:\nreturn {\n resolve: (info: HostComponentInfo) =>\n info.isTreeDurable ? tenantSubTreeId : contextId,\n payload: { tenantId },\n }\n"),e.qZA()(),e.TgZ(317,"p"),e._uU(318,"Now whenever you inject the "),e.TgZ(319,"code"),e._uU(320,"REQUEST"),e.qZA(),e._uU(321," provider (or "),e.TgZ(322,"code"),e._uU(323,"CONTEXT"),e.qZA(),e._uU(324," for GraphQL applications) using the "),e.TgZ(325,"code"),e._uU(326,"@Inject(REQUEST)"),e.qZA(),e._uU(327,"/"),e.TgZ(328,"code"),e._uU(329,"@Inject(CONTEXT)"),e.qZA(),e._uU(330,", the "),e.TgZ(331,"code"),e._uU(332,"payload"),e.qZA(),e._uU(333," object would be injected (consisting of a single property - "),e.TgZ(334,"code"),e._uU(335,"tenantId"),e.qZA(),e._uU(336," in this case)."),e.qZA(),e.TgZ(337,"p"),e._uU(338,"Alright so with this strategy in place, you can register it somewhere in your code (as it applies globally anyway), so for example, you could place it in the "),e.TgZ(339,"code"),e._uU(340,"main.ts"),e.qZA(),e._uU(341," file:"),e.qZA(),e.TgZ(342,"pre")(343,"code",9),e._uU(344,"\nContextIdFactory.apply(new AggregateByTenantContextIdStrategy());\n"),e.qZA()(),e.TgZ(345,"blockquote",7)(346,"strong"),e._uU(347,"Hint"),e.qZA(),e._uU(348," The "),e.TgZ(349,"code"),e._uU(350,"ContextIdFactory"),e.qZA(),e._uU(351," class is imported from the "),e.TgZ(352,"code"),e._uU(353,"@nestjs/core"),e.qZA(),e._uU(354," package.\n"),e.qZA(),e.TgZ(355,"p"),e._uU(356,"As long as the registration occurs before any request hits your application, everything will work as intended."),e.qZA(),e.TgZ(357,"p"),e._uU(358,"Lastly, to turn a regular provider into a durable provider, simply set the "),e.TgZ(359,"code"),e._uU(360,"durable"),e.qZA(),e._uU(361," flag to "),e.TgZ(362,"code"),e._uU(363,"true"),e.qZA(),e._uU(364," and change its scope to "),e.TgZ(365,"code"),e._uU(366,"Scope.REQUEST"),e.qZA(),e._uU(367," (not needed if the REQUEST scope is in the injection chain already):"),e.qZA(),e.TgZ(368,"pre")(369,"code",9),e._uU(370,"\nimport { Injectable, Scope } from '@nestjs/common';\n\n@Injectable({ scope: Scope.REQUEST, durable: true })\nexport class CatsService {}\n"),e.qZA()(),e.TgZ(371,"p"),e._uU(372,"Similarly, for "),e.TgZ(373,"a",10),e._uU(374,"custom providers"),e.qZA(),e._uU(375,", set the "),e.TgZ(376,"code"),e._uU(377,"durable"),e.qZA(),e._uU(378," property in the long-hand form for a provider registration:"),e.qZA(),e.TgZ(379,"pre")(380,"code",9),e._uU(381,"\n{\n provide: 'foobar',\n useFactory: () => { ... },\n scope: Scope.REQUEST,\n durable: true,\n}\n"),e.qZA()()())},dependencies:[l.U,m.f,p.rH],encapsulation:2,changeDetection:0})}return t})(),data:{title:"Injection scopes"}},{path:"execution-context",component:(()=>{class t extends d.y{static \u0275fac=function(){let o;return function(s){return(o||(o=e.n5z(t)))(s||t)}}();static \u0275cmp=e.Xpm({type:t,selectors:[["app-execution-context"]],features:[e.qOj],decls:615,vars:72,consts:[[1,"content"],["contentReference",""],[1,"github-links"],["href","https://github.com/ChuTingzj/docs.nestjs.zh-cn.com/tree/master/content/fundamentals/execution-context.md","aria-label","Suggest Edits","title","Suggest Edits"],[1,"fas","fa-edit"],["id","execution-context"],["routerLink","/guards"],["routerLink","/exception-filters"],["routerLink","/interceptors"],["appAnchor","","id","argumentshost-class"],["rel","nofollow","target","_blank","href","https://docs.nestjs.com/exception-filters#arguments-host"],["routerLink","/graphql/quick-start"],["appAnchor","","id","current-application-context"],[1,"language-typescript"],[1,"info"],["appAnchor","","id","host-handler-arguments"],["appAnchor","","id","executioncontext-class"],["rel","nofollow","target","_blank","href","https://docs.nestjs.com/guards#execution-context"],["rel","nofollow","target","_blank","href","https://docs.nestjs.com/interceptors#execution-context"],["appAnchor","","id","reflection-and-metadata"],[1,"filename"],["appa68c221306539e9d51fd09be6eb186c45f847229",""],[1,"language-ts"],["app8c5609ac60ce8db0a168b8218807000894e95e20",""],["app70a2896cce9eab3b43ec508cb29f92fe16f985c6",""],["appa87a1245d6b7538a9c957f8e875a606c700db710",""],["app5407a9e8e49140710a2b98edcd5759d5bda1f215",""],["appa264c31353ada56bb5adae1dd346683a2cf4255e",""],["appAnchor","","id","low-level-approach"],["app20e1104a78bb0afb669ecc4b918bc6a04535c77a",""],["app3b5ef7841eec9e1f765d86aef6d062329157844f",""],["appaa981e7e12036174c60db6acab5549db8553030d",""],["appca6aa15b84769ca402b94baa5782dec5793bbf8b",""]],template:function(n,s){if(1&n&&(e.TgZ(0,"div",0,1)(2,"div",2)(3,"a",3),e._UZ(4,"i",4),e.qZA()(),e.TgZ(5,"h3",5),e._uU(6,"Execution context"),e.qZA(),e.TgZ(7,"p"),e._uU(8,"Nest provides several utility classes that help make it easy to write applications that function across multiple application contexts (e.g., Nest HTTP server-based, microservices and WebSockets application contexts). These utilities provide information about the current execution context which can be used to build generic "),e.TgZ(9,"a",6),e._uU(10,"guards"),e.qZA(),e._uU(11,", "),e.TgZ(12,"a",7),e._uU(13,"filters"),e.qZA(),e._uU(14,", and "),e.TgZ(15,"a",8),e._uU(16,"interceptors"),e.qZA(),e._uU(17," that can work across a broad set of controllers, methods, and execution contexts."),e.qZA(),e.TgZ(18,"p"),e._uU(19,"We cover two such classes in this chapter: "),e.TgZ(20,"code"),e._uU(21,"ArgumentsHost"),e.qZA(),e._uU(22," and "),e.TgZ(23,"code"),e._uU(24,"ExecutionContext"),e.qZA(),e._uU(25,"."),e.qZA(),e.TgZ(26,"h4",9)(27,"span"),e._uU(28,"ArgumentsHost class"),e.qZA()(),e.TgZ(29,"p"),e._uU(30,"The "),e.TgZ(31,"code"),e._uU(32,"ArgumentsHost"),e.qZA(),e._uU(33," class provides methods for retrieving the arguments being passed to a handler. It allows choosing the appropriate context (e.g., HTTP, RPC (microservice), or WebSockets) to retrieve the arguments from. The framework provides an instance of "),e.TgZ(34,"code"),e._uU(35,"ArgumentsHost"),e.qZA(),e._uU(36,", typically referenced as a "),e.TgZ(37,"code"),e._uU(38,"host"),e.qZA(),e._uU(39," parameter, in places where you may want to access it. For example, the "),e.TgZ(40,"code"),e._uU(41,"catch()"),e.qZA(),e._uU(42," method of an "),e.TgZ(43,"a",10),e._uU(44,"exception filter"),e.qZA(),e._uU(45," is called with an "),e.TgZ(46,"code"),e._uU(47,"ArgumentsHost"),e.qZA(),e._uU(48,"instance."),e.qZA(),e.TgZ(49,"p")(50,"code"),e._uU(51,"ArgumentsHost"),e.qZA(),e._uU(52," simply acts as an abstraction over a handler's arguments. For example, for HTTP server applications (when "),e.TgZ(53,"code"),e._uU(54,"@nestjs/platform-express"),e.qZA(),e._uU(55," is being used), the "),e.TgZ(56,"code"),e._uU(57,"host"),e.qZA(),e._uU(58," object encapsulates Express's "),e.TgZ(59,"code"),e._uU(60,"[request, response, next]"),e.qZA(),e._uU(61," array, where "),e.TgZ(62,"code"),e._uU(63,"request"),e.qZA(),e._uU(64," is the request object, "),e.TgZ(65,"code"),e._uU(66,"response"),e.qZA(),e._uU(67," is the response object, and "),e.TgZ(68,"code"),e._uU(69,"next"),e.qZA(),e._uU(70," is a function that controls the application's request-response cycle. On the other hand, for "),e.TgZ(71,"a",11),e._uU(72,"GraphQL"),e.qZA(),e._uU(73," applications, the "),e.TgZ(74,"code"),e._uU(75,"host"),e.qZA(),e._uU(76," object contains the "),e.TgZ(77,"code"),e._uU(78,"[root, args, context, info]"),e.qZA(),e._uU(79," array."),e.qZA(),e.TgZ(80,"h4",12)(81,"span"),e._uU(82,"Current application context"),e.qZA()(),e.TgZ(83,"p"),e._uU(84,"When building generic "),e.TgZ(85,"a",6),e._uU(86,"guards"),e.qZA(),e._uU(87,", "),e.TgZ(88,"a",7),e._uU(89,"filters"),e.qZA(),e._uU(90,", and "),e.TgZ(91,"a",8),e._uU(92,"interceptors"),e.qZA(),e._uU(93," which are meant to run across multiple application contexts, we need a way to determine the type of application that our method is currently running in. Do this with the "),e.TgZ(94,"code"),e._uU(95,"getType()"),e.qZA(),e._uU(96," method of "),e.TgZ(97,"code"),e._uU(98,"ArgumentsHost"),e.qZA(),e._uU(99,":"),e.qZA(),e.TgZ(100,"pre")(101,"code",13),e._uU(102,"\nif (host.getType() === 'http') {\n // do something that is only important in the context of regular HTTP requests (REST)\n} else if (host.getType() === 'rpc') {\n // do something that is only important in the context of Microservice requests\n} else if (host.getType<GqlContextType>() === 'graphql') {\n // do something that is only important in the context of GraphQL requests\n}\n"),e.qZA()(),e.TgZ(103,"blockquote",14)(104,"strong"),e._uU(105,"Hint"),e.qZA(),e._uU(106," The "),e.TgZ(107,"code"),e._uU(108,"GqlContextType"),e.qZA(),e._uU(109," is imported from the "),e.TgZ(110,"code"),e._uU(111,"@nestjs/graphql"),e.qZA(),e._uU(112," package.\n"),e.qZA(),e.TgZ(113,"p"),e._uU(114,"With the application type available, we can write more generic components, as shown below."),e.qZA(),e.TgZ(115,"h4",15)(116,"span"),e._uU(117,"Host handler arguments"),e.qZA()(),e.TgZ(118,"p"),e._uU(119,"To retrieve the array of arguments being passed to the handler, one approach is to use the host object's "),e.TgZ(120,"code"),e._uU(121,"getArgs()"),e.qZA(),e._uU(122," method."),e.qZA(),e.TgZ(123,"pre")(124,"code",13),e._uU(125,"\nconst [req, res, next] = host.getArgs();\n"),e.qZA()(),e.TgZ(126,"p"),e._uU(127,"You can pluck a particular argument by index using the "),e.TgZ(128,"code"),e._uU(129,"getArgByIndex()"),e.qZA(),e._uU(130," method:"),e.qZA(),e.TgZ(131,"pre")(132,"code",13),e._uU(133,"\nconst request = host.getArgByIndex(0);\nconst response = host.getArgByIndex(1);\n"),e.qZA()(),e.TgZ(134,"p"),e._uU(135,"In these examples we retrieved the request and response objects by index, which is not typically recommended as it couples the application to a particular execution context. Instead, you can make your code more robust and reusable by using one of the "),e.TgZ(136,"code"),e._uU(137,"host"),e.qZA(),e._uU(138," object's utility methods to switch to the appropriate application context for your application. The context switch utility methods are shown below."),e.qZA(),e.TgZ(139,"pre")(140,"code",13),e._uU(141,"\n/**\n * Switch context to RPC.\n */\nswitchToRpc(): RpcArgumentsHost;\n/**\n * Switch context to HTTP.\n */\nswitchToHttp(): HttpArgumentsHost;\n/**\n * Switch context to WebSockets.\n */\nswitchToWs(): WsArgumentsHost;\n"),e.qZA()(),e.TgZ(142,"p"),e._uU(143,"Let's rewrite the previous example using the "),e.TgZ(144,"code"),e._uU(145,"switchToHttp()"),e.qZA(),e._uU(146," method. The "),e.TgZ(147,"code"),e._uU(148,"host.switchToHttp()"),e.qZA(),e._uU(149," helper call returns an "),e.TgZ(150,"code"),e._uU(151,"HttpArgumentsHost"),e.qZA(),e._uU(152," object that is appropriate for the HTTP application context. The "),e.TgZ(153,"code"),e._uU(154,"HttpArgumentsHost"),e.qZA(),e._uU(155," object has two useful methods we can use to extract the desired objects. We also use the Express type assertions in this case to return native Express typed objects:"),e.qZA(),e.TgZ(156,"pre")(157,"code",13),e._uU(158,"\nconst ctx = host.switchToHttp();\nconst request = ctx.getRequest<Request>();\nconst response = ctx.getResponse<Response>();\n"),e.qZA()(),e.TgZ(159,"p"),e._uU(160,"Similarly "),e.TgZ(161,"code"),e._uU(162,"WsArgumentsHost"),e.qZA(),e._uU(163," and "),e.TgZ(164,"code"),e._uU(165,"RpcArgumentsHost"),e.qZA(),e._uU(166," have methods to return appropriate objects in the microservices and WebSockets contexts. Here are the methods for "),e.TgZ(167,"code"),e._uU(168,"WsArgumentsHost"),e.qZA(),e._uU(169,":"),e.qZA(),e.TgZ(170,"pre")(171,"code",13),e._uU(172,"\nexport interface WsArgumentsHost {\n /**\n * Returns the data object.\n */\n getData<T>(): T;\n /**\n * Returns the client object.\n */\n getClient<T>(): T;\n}\n"),e.qZA()(),e.TgZ(173,"p"),e._uU(174,"Following are the methods for "),e.TgZ(175,"code"),e._uU(176,"RpcArgumentsHost"),e.qZA(),e._uU(177,":"),e.qZA(),e.TgZ(178,"pre")(179,"code",13),e._uU(180,"\nexport interface RpcArgumentsHost {\n /**\n * Returns the data object.\n */\n getData<T>(): T;\n\n /**\n * Returns the context object.\n */\n getContext<T>(): T;\n}\n"),e.qZA()(),e.TgZ(181,"h4",16)(182,"span"),e._uU(183,"ExecutionContext class"),e.qZA()(),e.TgZ(184,"p")(185,"code"),e._uU(186,"ExecutionContext"),e.qZA(),e._uU(187," extends "),e.TgZ(188,"code"),e._uU(189,"ArgumentsHost"),e.qZA(),e._uU(190,", providing additional details about the current execution process. Like "),e.TgZ(191,"code"),e._uU(192,"ArgumentsHost"),e.qZA(),e._uU(193,", Nest provides an instance of "),e.TgZ(194,"code"),e._uU(195,"ExecutionContext"),e.qZA(),e._uU(196," in places you may need it, such as in the "),e.TgZ(197,"code"),e._uU(198,"canActivate()"),e.qZA(),e._uU(199," method of a "),e.TgZ(200,"a",17),e._uU(201,"guard"),e.qZA(),e._uU(202," and the "),e.TgZ(203,"code"),e._uU(204,"intercept()"),e.qZA(),e._uU(205," method of an "),e.TgZ(206,"a",18),e._uU(207,"interceptor"),e.qZA(),e._uU(208,". It provides the following methods:"),e.qZA(),e.TgZ(209,"pre")(210,"code",13),e._uU(211,"\nexport interface ExecutionContext extends ArgumentsHost {\n /**\n * Returns the type of the controller class which the current handler belongs to.\n */\n getClass<T>(): Type<T>;\n /**\n * Returns a reference to the handler (method) that will be invoked next in the\n * request pipeline.\n */\n getHandler(): Function;\n}\n"),e.qZA()(),e.TgZ(212,"p"),e._uU(213,"The "),e.TgZ(214,"code"),e._uU(215,"getHandler()"),e.qZA(),e._uU(216," method returns a reference to the handler about to be invoked. The "),e.TgZ(217,"code"),e._uU(218,"getClass()"),e.qZA(),e._uU(219," method returns the type of the "),e.TgZ(220,"code"),e._uU(221,"Controller"),e.qZA(),e._uU(222," class which this particular handler belongs to. For example, in an HTTP context, if the currently processed request is a "),e.TgZ(223,"code"),e._uU(224,"POST"),e.qZA(),e._uU(225," request, bound to the "),e.TgZ(226,"code"),e._uU(227,"create()"),e.qZA(),e._uU(228," method on the "),e.TgZ(229,"code"),e._uU(230,"CatsController"),e.qZA(),e._uU(231,", "),e.TgZ(232,"code"),e._uU(233,"getHandler()"),e.qZA(),e._uU(234," returns a reference to the "),e.TgZ(235,"code"),e._uU(236,"create()"),e.qZA(),e._uU(237," method and "),e.TgZ(238,"code"),e._uU(239,"getClass()"),e.qZA(),e._uU(240," returns the "),e.TgZ(241,"code"),e._uU(242,"CatsController"),e.qZA(),e.TgZ(243,"strong"),e._uU(244,"type"),e.qZA(),e._uU(245," (not instance)."),e.qZA(),e.TgZ(246,"pre")(247,"code",13),e._uU(248,'\nconst methodKey = ctx.getHandler().name; // "create"\nconst className = ctx.getClass().name; // "CatsController"\n'),e.qZA()(),e.TgZ(249,"p"),e._uU(250,"The ability to access references to both the current class and handler method provides great flexibility. Most importantly, it gives us the opportunity to access the metadata set through either decorators created via "),e.TgZ(251,"code"),e._uU(252,"Reflector#createDecorator"),e.qZA(),e._uU(253," or the built-in "),e.TgZ(254,"code"),e._uU(255,"@SetMetadata()"),e.qZA(),e._uU(256," decorator from within guards or interceptors. We cover this use case below."),e.qZA(),e.TgZ(257,"p"),e._UZ(258,"app-banner-enterprise"),e.qZA(),e.TgZ(259,"h4",19)(260,"span"),e._uU(261,"Reflection and metadata"),e.qZA()(),e.TgZ(262,"p"),e._uU(263,"Nest provides the ability to attach "),e.TgZ(264,"strong"),e._uU(265,"custom metadata"),e.qZA(),e._uU(266," to route handlers through decorators created via "),e.TgZ(267,"code"),e._uU(268,"Reflector#createDecorator"),e.qZA(),e._uU(269," method, and the built-in "),e.TgZ(270,"code"),e._uU(271,"@SetMetadata()"),e.qZA(),e._uU(272," decorator. In this section, let's compare the two approaches and see how to access the metadata from within a guard or interceptor."),e.qZA(),e.TgZ(273,"p"),e._uU(274,"To create strongly-typed decorators using "),e.TgZ(275,"code"),e._uU(276,"Reflector#createDecorator"),e.qZA(),e._uU(277,", we need to specify the type argument. For example, let's create a "),e.TgZ(278,"code"),e._uU(279,"Roles"),e.qZA(),e._uU(280," decorator that takes an array of strings as an argument."),e.qZA(),e.TgZ(281,"span",20),e._uU(282),e.ALo(283,"extension"),e._UZ(284,"app-tabs",null,21),e.qZA(),e.TgZ(286,"pre")(287,"code",22),e._uU(288,"\nimport { Reflector } from '@nestjs/core';\n\nexport const Roles = Reflector.createDecorator<string[]>();\n"),e.qZA()(),e.TgZ(289,"p"),e._uU(290,"The "),e.TgZ(291,"code"),e._uU(292,"Roles"),e.qZA(),e._uU(293," decorator here is a function that takes a single argument of type "),e.TgZ(294,"code"),e._uU(295,"string[]"),e.qZA(),e._uU(296,"."),e.qZA(),e.TgZ(297,"p"),e._uU(298,"Now, to use this decorator, we simply annotate the handler with it:"),e.qZA(),e.TgZ(299,"span",20),e._uU(300),e.ALo(301,"extension"),e._UZ(302,"app-tabs",null,23),e.qZA(),e.TgZ(304,"pre")(305,"code",13),e._uU(306,"\n@Post()\n@Roles(['admin'])\nasync create(@Body() createCatDto: CreateCatDto) {\n this.catsService.create(createCatDto);\n}\n"),e.qZA()(),e.TgZ(307,"pre")(308,"code",13),e._uU(309,"\n@Post()\n@Roles(['admin'])\n@Bind(Body())\nasync create(createCatDto) {\n this.catsService.create(createCatDto);\n}\n"),e.qZA()(),e.TgZ(310,"p"),e._uU(311,"Here we've attached the "),e.TgZ(312,"code"),e._uU(313,"Roles"),e.qZA(),e._uU(314," decorator metadata to the "),e.TgZ(315,"code"),e._uU(316,"create()"),e.qZA(),e._uU(317," method, indicating that only users with the "),e.TgZ(318,"code"),e._uU(319,"admin"),e.qZA(),e._uU(320," role should be allowed to access this route."),e.qZA(),e.TgZ(321,"p"),e._uU(322,"To access the route's role(s) (custom metadata), we'll use the "),e.TgZ(323,"code"),e._uU(324,"Reflector"),e.qZA(),e._uU(325," helper class again. "),e.TgZ(326,"code"),e._uU(327,"Reflector"),e.qZA(),e._uU(328," can be injected into a class in the normal way:"),e.qZA(),e.TgZ(329,"span",20),e._uU(330),e.ALo(331,"extension"),e._UZ(332,"app-tabs",null,24),e.qZA(),e.TgZ(334,"pre")(335,"code",13),e._uU(336,"\n@Injectable()\nexport class RolesGuard {\n constructor(private reflector: Reflector) {}\n}\n"),e.qZA()(),e.TgZ(337,"pre")(338,"code",13),e._uU(339,"\n@Injectable()\n@Dependencies(Reflector)\nexport class CatsService {\n constructor(reflector) {\n this.reflector = reflector;\n }\n}\n"),e.qZA()(),e.TgZ(340,"blockquote",14)(341,"strong"),e._uU(342,"Hint"),e.qZA(),e._uU(343," The "),e.TgZ(344,"code"),e._uU(345,"Reflector"),e.qZA(),e._uU(346," class is imported from the "),e.TgZ(347,"code"),e._uU(348,"@nestjs/core"),e.qZA(),e._uU(349," package.\n"),e.qZA(),e.TgZ(350,"p"),e._uU(351,"Now, to read the handler metadata, use the "),e.TgZ(352,"code"),e._uU(353,"get()"),e.qZA(),e._uU(354," method:"),e.qZA(),e.TgZ(355,"pre")(356,"code",13),e._uU(357,"\nconst roles = this.reflector.get(Roles, context.getHandler());\n"),e.qZA()(),e.TgZ(358,"p"),e._uU(359,"The "),e.TgZ(360,"code"),e._uU(361,"Reflector#get"),e.qZA(),e._uU(362," method allows us to easily access the metadata by passing in two arguments: a decorator reference and a "),e.TgZ(363,"strong"),e._uU(364,"context"),e.qZA(),e._uU(365," (decorator target) to retrieve the metadata from. In this example, the specified "),e.TgZ(366,"strong"),e._uU(367,"decorator"),e.qZA(),e._uU(368," is "),e.TgZ(369,"code"),e._uU(370,"Roles"),e.qZA(),e._uU(371," (refer back to the "),e.TgZ(372,"code"),e._uU(373,"roles.decorator.ts"),e.qZA(),e._uU(374," file above). The context is provided by the call to "),e.TgZ(375,"code"),e._uU(376,"context.getHandler()"),e.qZA(),e._uU(377,", which results in extracting the metadata for the currently processed route handler. Remember, "),e.TgZ(378,"code"),e._uU(379,"getHandler()"),e.qZA(),e._uU(380," gives us a "),e.TgZ(381,"strong"),e._uU(382,"reference"),e.qZA(),e._uU(383," to the route handler function."),e.qZA(),e.TgZ(384,"p"),e._uU(385,"Alternatively, we may organize our controller by applying metadata at the controller level, applying to all routes in the controller class."),e.qZA(),e.TgZ(386,"span",20),e._uU(387),e.ALo(388,"extension"),e._UZ(389,"app-tabs",null,25),e.qZA(),e.TgZ(391,"pre")(392,"code",13),e._uU(393,"\n@Roles(['admin'])\n@Controller('cats')\nexport class CatsController {}\n"),e.qZA()(),e.TgZ(394,"pre")(395,"code",13),e._uU(396,"\n@Roles(['admin'])\n@Controller('cats')\nexport class CatsController {}\n"),e.qZA()(),e.TgZ(397,"p"),e._uU(398,"In this case, to extract controller metadata, we pass "),e.TgZ(399,"code"),e._uU(400,"context.getClass()"),e.qZA(),e._uU(401," as the second argument (to provide the controller class as the context for metadata extraction) instead of "),e.TgZ(402,"code"),e._uU(403,"context.getHandler()"),e.qZA(),e._uU(404,":"),e.qZA(),e.TgZ(405,"span",20),e._uU(406),e.ALo(407,"extension"),e._UZ(408,"app-tabs",null,26),e.qZA(),e.TgZ(410,"pre")(411,"code",13),e._uU(412,"\nconst roles = this.reflector.get(Roles, context.getClass());\n"),e.qZA()(),e.TgZ(413,"p"),e._uU(414,"Given the ability to provide metadata at multiple levels, you may need to extract and merge metadata from several contexts. The "),e.TgZ(415,"code"),e._uU(416,"Reflector"),e.qZA(),e._uU(417," class provides two utility methods used to help with this. These methods extract "),e.TgZ(418,"strong"),e._uU(419,"both"),e.qZA(),e._uU(420," controller and method metadata at once, and combine them in different ways."),e.qZA(),e.TgZ(421,"p"),e._uU(422,"Consider the following scenario, where you've supplied "),e.TgZ(423,"code"),e._uU(424,"Roles"),e.qZA(),e._uU(425," metadata at both levels."),e.qZA(),e.TgZ(426,"span",20),e._uU(427),e.ALo(428,"extension"),e._UZ(429,"app-tabs",null,27),e.qZA(),e.TgZ(431,"pre")(432,"code",13),e._uU(433,"\n@Roles(['user'])\n@Controller('cats')\nexport class CatsController {\n @Post()\n @Roles(['admin'])\n async create(@Body() createCatDto: CreateCatDto) {\n this.catsService.create(createCatDto);\n }\n}\n"),e.qZA()(),e.TgZ(434,"pre")(435,"code",13),e._uU(436,"\n@Roles(['user'])\n@Controller('cats')\nexport class CatsController {}\n @Post()\n @Roles(['admin'])\n @Bind(Body())\n async create(createCatDto) {\n this.catsService.create(createCatDto);\n }\n}\n"),e.qZA()(),e.TgZ(437,"p"),e._uU(438,"If your intent is to specify "),e.TgZ(439,"code"),e._uU(440,"'user'"),e.qZA(),e._uU(441," as the default role, and override it selectively for certain methods, you would probably use the "),e.TgZ(442,"code"),e._uU(443,"getAllAndOverride()"),e.qZA(),e._uU(444," method."),e.qZA(),e.TgZ(445,"pre")(446,"code",13),e._uU(447,"\nconst roles = this.reflector.getAllAndOverride(Roles, [context.getHandler(), context.getClass()]);\n"),e.qZA()(),e.TgZ(448,"p"),e._uU(449,"A guard with this code, running in the context of the "),e.TgZ(450,"code"),e._uU(451,"create()"),e.qZA(),e._uU(452," method, with the above metadata, would result in "),e.TgZ(453,"code"),e._uU(454,"roles"),e.qZA(),e._uU(455," containing "),e.TgZ(456,"code"),e._uU(457,"['admin']"),e.qZA(),e._uU(458,"."),e.qZA(),e.TgZ(459,"p"),e._uU(460,"To get metadata for both and merge it (this method merges both arrays and objects), use the "),e.TgZ(461,"code"),e._uU(462,"getAllAndMerge()"),e.qZA(),e._uU(463," method:"),e.qZA(),e.TgZ(464,"pre")(465,"code",13),e._uU(466,"\nconst roles = this.reflector.getAllAndMerge(Roles, [context.getHandler(), context.getClass()]);\n"),e.qZA()(),e.TgZ(467,"p"),e._uU(468,"This would result in "),e.TgZ(469,"code"),e._uU(470,"roles"),e.qZA(),e._uU(471," containing "),e.TgZ(472,"code"),e._uU(473,"['user', 'admin']"),e.qZA(),e._uU(474,"."),e.qZA(),e.TgZ(475,"p"),e._uU(476,"For both of these merge methods, you pass the metadata key as the first argument, and an array of metadata target contexts (i.e., calls to the "),e.TgZ(477,"code"),e._uU(478,"getHandler()"),e.qZA(),e._uU(479," and/or "),e.TgZ(480,"code"),e._uU(481,"getClass())"),e.qZA(),e._uU(482," methods) as the second argument."),e.qZA(),e.TgZ(483,"h4",28)(484,"span"),e._uU(485,"Low-level approach"),e.qZA()(),e.TgZ(486,"p"),e._uU(487,"As mentioned earlier, instead of using "),e.TgZ(488,"code"),e._uU(489,"Reflector#createDecorator"),e.qZA(),e._uU(490,", you can also use the built-in "),e.TgZ(491,"code"),e._uU(492,"@SetMetadata()"),e.qZA(),e._uU(493," decorator to attach metadata to a handler."),e.qZA(),e.TgZ(494,"span",20),e._uU(495),e.ALo(496,"extension"),e._UZ(497,"app-tabs",null,29),e.qZA(),e.TgZ(499,"pre")(500,"code",13),e._uU(501,"\n@Post()\n@SetMetadata('roles', ['admin'])\nasync create(@Body() createCatDto: CreateCatDto) {\n this.catsService.create(createCatDto);\n}\n"),e.qZA()(),e.TgZ(502,"pre")(503,"code",13),e._uU(504,"\n@Post()\n@SetMetadata('roles', ['admin'])\n@Bind(Body())\nasync create(createCatDto) {\n this.catsService.create(createCatDto);\n}\n"),e.qZA()(),e.TgZ(505,"blockquote",14)(506,"strong"),e._uU(507,"Hint"),e.qZA(),e._uU(508," The "),e.TgZ(509,"code"),e._uU(510,"@SetMetadata()"),e.qZA(),e._uU(511," decorator is imported from the "),e.TgZ(512,"code"),e._uU(513,"@nestjs/common"),e.qZA(),e._uU(514," package.\n"),e.qZA(),e.TgZ(515,"p"),e._uU(516,"With the construction above, we attached the "),e.TgZ(517,"code"),e._uU(518,"roles"),e.qZA(),e._uU(519," metadata ("),e.TgZ(520,"code"),e._uU(521,"roles"),e.qZA(),e._uU(522," is a metadata key and "),e.TgZ(523,"code"),e._uU(524,"['admin']"),e.qZA(),e._uU(525," is the associated value) to the "),e.TgZ(526,"code"),e._uU(527,"create()"),e.qZA(),e._uU(528," method. While this works, it's not good practice to use "),e.TgZ(529,"code"),e._uU(530,"@SetMetadata()"),e.qZA(),e._uU(531," directly in your routes. Instead, you can create your own decorators, as shown below:"),e.qZA(),e.TgZ(532,"span",20),e._uU(533),e.ALo(534,"extension"),e._UZ(535,"app-tabs",null,30),e.qZA(),e.TgZ(537,"pre")(538,"code",13),e._uU(539,"\nimport { SetMetadata } from '@nestjs/common';\n\nexport const Roles = (...roles: string[]) => SetMetadata('roles', roles);\n"),e.qZA()(),e.TgZ(540,"pre")(541,"code",13),e._uU(542,"\nimport { SetMetadata } from '@nestjs/common';\n\nexport const Roles = (...roles) => SetMetadata('roles', roles);\n"),e.qZA()(),e.TgZ(543,"p"),e._uU(544,"This approach is much cleaner and more readable, and somewhat resembles the "),e.TgZ(545,"code"),e._uU(546,"Reflector#createDecorator"),e.qZA(),e._uU(547," approach. The difference is that with "),e.TgZ(548,"code"),e._uU(549,"@SetMetadata"),e.qZA(),e._uU(550," you have more control over the metadata key and value, and also can create decorators that take more than one argument."),e.qZA(),e.TgZ(551,"p"),e._uU(552,"Now that we have a custom "),e.TgZ(553,"code"),e._uU(554,"@Roles()"),e.qZA(),e._uU(555," decorator, we can use it to decorate the "),e.TgZ(556,"code"),e._uU(557,"create()"),e.qZA(),e._uU(558," method."),e.qZA(),e.TgZ(559,"span",20),e._uU(560),e.ALo(561,"extension"),e._UZ(562,"app-tabs",null,31),e.qZA(),e.TgZ(564,"pre")(565,"code",13),e._uU(566,"\n@Post()\n@Roles('admin')\nasync create(@Body() createCatDto: CreateCatDto) {\n this.catsService.create(createCatDto);\n}\n"),e.qZA()(),e.TgZ(567,"pre")(568,"code",13),e._uU(569,"\n@Post()\n@Roles('admin')\n@Bind(Body())\nasync create(createCatDto) {\n this.catsService.create(createCatDto);\n}\n"),e.qZA()(),e.TgZ(570,"p"),e._uU(571,"To access the route's role(s) (custom metadata), we'll use the "),e.TgZ(572,"code"),e._uU(573,"Reflector"),e.qZA(),e._uU(574," helper class again:"),e.qZA(),e.TgZ(575,"span",20),e._uU(576),e.ALo(577,"extension"),e._UZ(578,"app-tabs",null,32),e.qZA(),e.TgZ(580,"pre")(581,"code",13),e._uU(582,"\n@Injectable()\nexport class RolesGuard {\n constructor(private reflector: Reflector) {}\n}\n"),e.qZA()(),e.TgZ(583,"pre")(584,"code",13),e._uU(585,"\n@Injectable()\n@Dependencies(Reflector)\nexport class CatsService {\n constructor(reflector) {\n this.reflector = reflector;\n }\n}\n"),e.qZA()(),e.TgZ(586,"blockquote",14)(587,"strong"),e._uU(588,"Hint"),e.qZA(),e._uU(589," The "),e.TgZ(590,"code"),e._uU(591,"Reflector"),e.qZA(),e._uU(592," class is imported from the "),e.TgZ(593,"code"),e._uU(594,"@nestjs/core"),e.qZA(),e._uU(595," package.\n"),e.qZA(),e.TgZ(596,"p"),e._uU(597,"Now, to read the handler metadata, use the "),e.TgZ(598,"code"),e._uU(599,"get()"),e.qZA(),e._uU(600," method."),e.qZA(),e.TgZ(601,"pre")(602,"code",13),e._uU(603,"\nconst roles = this.reflector.get<string[]>('roles', context.getHandler());\n"),e.qZA()(),e.TgZ(604,"p"),e._uU(605,"Here instead of passing a decorator reference, we pass the metadata "),e.TgZ(606,"strong"),e._uU(607,"key"),e.qZA(),e._uU(608," as the first argument (which in our case is "),e.TgZ(609,"code"),e._uU(610,"'roles'"),e.qZA(),e._uU(611,"). Everything else remains the same as in the "),e.TgZ(612,"code"),e._uU(613,"Reflector#createDecorator"),e.qZA(),e._uU(614," example."),e.qZA()()),2&n){const a=e.MAs(285),r=e.MAs(303),i=e.MAs(333),u=e.MAs(390),_=e.MAs(409),g=e.MAs(430),Z=e.MAs(498),A=e.MAs(536),f=e.MAs(563),T=e.MAs(579);e.xp6(282),e.hij(" ",e.xi3(283,42,"roles.decorator",a.isJsActive),"\n"),e.xp6(18),e.hij(" ",e.xi3(301,45,"cats.controller",r.isJsActive),"\n"),e.xp6(4),e.ekj("hide",r.isJsActive),e.xp6(3),e.ekj("hide",!r.isJsActive),e.xp6(23),e.hij(" ",e.xi3(331,48,"roles.guard",i.isJsActive),"\n"),e.xp6(4),e.ekj("hide",i.isJsActive),e.xp6(3),e.ekj("hide",!i.isJsActive),e.xp6(50),e.hij(" ",e.xi3(388,51,"cats.controller",u.isJsActive),"\n"),e.xp6(4),e.ekj("hide",u.isJsActive),e.xp6(3),e.ekj("hide",!u.isJsActive),e.xp6(12),e.hij(" ",e.xi3(407,54,"roles.guard",_.isJsActive),"\n"),e.xp6(21),e.hij(" ",e.xi3(428,57,"cats.controller",g.isJsActive),"\n"),e.xp6(4),e.ekj("hide",g.isJsActive),e.xp6(3),e.ekj("hide",!g.isJsActive),e.xp6(61),e.hij(" ",e.xi3(496,60,"cats.controller",Z.isJsActive),"\n"),e.xp6(4),e.ekj("hide",Z.isJsActive),e.xp6(3),e.ekj("hide",!Z.isJsActive),e.xp6(31),e.hij(" ",e.xi3(534,63,"roles.decorator",A.isJsActive),"\n"),e.xp6(4),e.ekj("hide",A.isJsActive),e.xp6(3),e.ekj("hide",!A.isJsActive),e.xp6(20),e.hij(" ",e.xi3(561,66,"cats.controller",f.isJsActive),"\n"),e.xp6(4),e.ekj("hide",f.isJsActive),e.xp6(3),e.ekj("hide",!f.isJsActive),e.xp6(9),e.hij(" ",e.xi3(577,69,"roles.guard",T.isJsActive),"\n"),e.xp6(4),e.ekj("hide",T.isJsActive),e.xp6(3),e.ekj("hide",!T.isJsActive)}},dependencies:[h.n,l.U,M.V,p.rH,U.F],encapsulation:2,changeDetection:0})}return t})(),data:{title:"Execution context"}},{path:"lifecycle-events",component:j,data:{title:"Lifecycle events"}},{path:"circular-dependency",component:x,data:{title:"Circular Dependency"}}];let R=(()=>{class t{static \u0275fac=function(n){return new(n||t)};static \u0275mod=e.oAB({type:t});static \u0275inj=e.cJS({imports:[y.ez,b.m,p.Bz.forChild(I)]})}return t})()}}]);
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化