Nest.js 中的 Monorepo 和 Microservice 设置
我们首先来定义一下什么是单体仓库(monorepo)。
monorepo(单体仓库的音节缩写)是一种软件开发策略,其中多个项目的代码存储在同一个仓库中。
我们不再为每个服务或应用程序创建一个 git 仓库,而是只创建一个 git 仓库,所有内容都将包含在其中。
这种代码组织方式有一些优点。
由于代码已经存在,因此代码重用非常容易。正确设置单体仓库后,更新依赖项也更加方便。
现在让我们来定义一下什么是“微服务”。
微服务是一种软件开发技术,它是面向服务架构(SOA)结构风格的一种变体,将应用程序组织成一组松散耦合的服务。在微服务架构中,服务粒度很细,协议也很轻量级。
我们不再把所有功能都放在一个应用/服务里,而是采用最小可复用的独立服务。这意味着每个服务都有自己的数据库,可以用不同的编程语言编写,而且应该易于替换。微服务是一个热门且重要的话题。和所有事物一样,它也有优缺点!如果您想了解更多关于微服务的信息,请在下方评论区留言,我会在下一篇博文中详细探讨!
Nestjs 中的 Monorepo
首先,我们需要安装 Nest CLI。
npm install -g @nestjs/cli
or
yarn global add @nestjs/cli
现在你nest的终端应该已经显示了该命令。
我们可以用以下命令进行测试:
nest --version
现在我们可以创建一个“标准”项目
nest new lampeweb
你可以选择使用哪种npm纱线yarn。因为我喜欢用纱线yarn,所以我总是选择纱线。
现在我们已经创建了一个标准项目,接下来需要将其转换为单体仓库(monorepo)。使用 Nest 可以轻松实现这一点,只需运行以下命令:
cd lampeweb
nest generate app blog
搞定!现在我们有了一个单体仓库。正如你所看到的,src原来的文件夹不见了,取而代之的是一个apps单独的文件夹。在这个apps文件夹里,我们可以找到我们的两个应用程序/微服务。
其中一个重要的文件是 `<filename>`nest-cli.json文件。打开该文件后,您可以看到一个包含大量条目的 JSON 配置文件。我们需要导入的条目是 `<import>` "root": "apps/lampeweb",。该条目告诉 Nest CLI 该项目的主文件位于何处。此外,您还可以找到 ` "projects": {<filename>` 条目。在这里,我们可以找到该项目中所有应用/服务的列表。
在此之前,我们需要更改blog应用程序的端口。
打开apps/blog/src/main.ts并修改以下行:
await app.listen(3000);
到
await app.listen(4000);
现在让我们开始提供服务。
nest start
以及第二个终端
nest start blog
所以第一条命令会启动我们的root应用程序。在本例中,就是这个lampeweb应用程序。第二条命令会启动博客服务。很简单,对吧?
现在我们有两个应用程序在同一个仓库中运行!
微服务
我们首先要做的是将 Nest 微服务包添加到我们的项目中。
yarn add @nestjs/microservices
首先,我们需要编辑apps/blog/src/main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { Transport } from '@nestjs/microservices';
import { Logger } from '@nestjs/common';
const logger = new Logger('Blog');
async function bootstrap() {
const app = await NestFactory.createMicroservice(AppModule, {
transport: Transport.TCP,
options: {
port: 4000,
},
});
await app.listen(() => logger.log('Microservice is listening'));
}
bootstrap();
我们已将其更改NestFactory.create为NestFactory.createMicroservice。这将告诉 Nest 此应用现在是一个微服务。我们现在也有了一个配置 JSON 文件。我们需要告诉 Nest 我们想要使用哪种传输方式。TCP是最简单的,不需要任何额外配置。我们还可以使用Redis、RabbitMQ等等。如果大家对本文感兴趣,我可以更详细地讲解这个主题。我们还需要将端口添加到配置 JSON 文件中。
我们需要编辑该应用/服务/微服务中的第二个文件是apps/blog/src/app.controller.ts。
我们需要改变
@Get()
getHello(): string {
return this.appService.getHello();
}
到
@MessagePattern('getHello')
getHello(name: string): string {
return this.appService.getHello(name);
}
现在我们不再使用 http 动词了,但是MessagePattern……通过这个'getHello'名称,我们之后可以调用该函数。
apps/blog/src/app.service.ts
我们需要修改的第三个文件是……
@Injectable()
export class AppService {
getHello(): string {
return 'Hello World!';
}
}
到
@Injectable()
export class AppService {
getHello(name: string): string {
return `Hello ${name}!`;
}
}
这样,getHello 消息就可以接受一个字符串,以便我们能够返回名称。
好了!我们的blog微服务就完成了。
在我们的lampeweb应用程序中,我们需要修改以下 文件apps/lampeweb/src/app.service.ts。
import { Injectable } from '@nestjs/common';
@Injectable()
export class AppService {
getHello(): string {
return 'Hello World!';
}
}
到
import { Injectable } from '@nestjs/common';
import {
ClientProxyFactory,
Transport,
ClientProxy,
} from '@nestjs/microservices';
@Injectable()
export class AppService {
private client: ClientProxy;
constructor() {
this.client = ClientProxyFactory.create({
transport: Transport.TCP,
options: {
port: 4000,
},
});
}
public getHello(): Promise<string> {
return this.client.send<string, string>('getHello', 'Michael').toPromise();
}
}
好的,看起来内容有点多!我们添加了一个constructor创建客户端的方法。我们需要告诉客户端我们要连接的微服务使用什么传输协议和端口。在实际应用中,还需要提供主机名,但这里我们省略了这一步,因为代码运行在同一台机器上。
现在我们只需要修改getHello方法,使其返回一个 Promise 对象。该send方法接受两个参数。第一个参数是我们要发送的消息名称,第二个参数是我们要发送的有效负载。在本例中,有效负载只是一个简单的名称字符串。
接下来我们需要修改的文件apps/lampeweb/src/app.controller.ts来自
import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get()
getHello(): string {
return this.appService.getHello();
}
}
到
import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get()
async getHello(): Promise<string> {
const helloValue = await this.appService.getHello();
return helloValue;
}
}
变化不大,只是我们现在期望 Promise 被解析为一个字符串。
好了!
现在需要重启这两个服务:
nest start
#and
nest start blog
如果需要,您还可以将该--watch标志添加到这两个命令中,以便 Nest 每次保存时都会重建服务。
现在我们只需要打开浏览器并访问http://localhost:3000/。
希望你喜欢这篇文章!如果你想看到后续内容,请评论、点赞和分享。这样我就知道你对这类内容感兴趣了!
👋打个招呼! Instagram | Twitter | LinkedIn | Medium | Twitch | YouTube
文章来源:https://dev.to/lampewebdev/monorepo-and-microservice-setup-in-nest-js-41n4
