发布于 2026-01-06 7 阅读
0

Nest.js 中的 Monorepo 和 Microservice 设置

Nest.js 中的 Monorepo 和 Microservice 设置

我们首先来定义一下什么是单体仓库(monorepo)。

monorepo(单体仓库的音节缩写)是一种软件开发策略,其中多个项目的代码存储在同一个仓库中。

我们不再为每个服务或应用程序创建一个 git 仓库,而是只创建一个 git 仓库,所有内容都将包含在其中。

这种代码组织方式有一些优点。
由于代码已经存在,因此代码重用非常容易。正确设置单体仓库后,更新依赖项也更加方便。

现在让我们来定义一下什么是“微服务”。

微服务是一种软件开发技术,它是面向服务架构(SOA)结构风格的一种变体,将应用程序组织成一组松散耦合的服务。在微服务架构中,服务粒度很细,协议也很轻量级。

我们不再把所有功能都放在一个应用/服务里,而是采用最小可复用的独立服务。这意味着每个服务都有自己的数据库,可以用不同的编程语言编写,而且应该易于替换。微服务是一个热门且重要的话题。和所有事物一样,它也有优缺点!如果您想了解更多关于微服务的信息,请在下方评论区留言,我会在下一篇博文中详细探讨!

Nestjs 中的 Monorepo

首先,我们需要安装 Nest CLI。



npm install -g @nestjs/cli
or
yarn global add @nestjs/cli


Enter fullscreen mode Exit fullscreen mode

现在你nest的终端应该已经显示了该命令。
我们可以用以下命令进行测试:



nest --version


Enter fullscreen mode Exit fullscreen mode

现在我们可以创建一个“标准”项目



nest new lampeweb


Enter fullscreen mode Exit fullscreen mode

你可以选择使用哪种npm纱线yarn。因为我喜欢用纱线yarn,所以我总是选择纱线。

现在我们已经创建了一个标准项目,接下来需要将其转换为单体仓库(monorepo)。使用 Nest 可以轻松实现这一点,只需运行以下命令:



cd lampeweb
nest generate app blog


Enter fullscreen mode Exit fullscreen mode

搞定!现在我们有了一个单体仓库。正如你所看到的,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);


Enter fullscreen mode Exit fullscreen mode



await app.listen(4000);


Enter fullscreen mode Exit fullscreen mode

现在让我们开始提供服务。



nest start


Enter fullscreen mode Exit fullscreen mode

以及第二个终端



nest start blog


Enter fullscreen mode Exit fullscreen mode

所以第一条命令会启动我们的root应用程序。在本例中,就是这个lampeweb应用程序。第二条命令会启动博客服务。很简单,对吧?

现在我们有两个应用程序在同一个仓库中运行!

微服务

我们首先要做的是将 Nest 微服务包添加到我们的项目中。



yarn add @nestjs/microservices


Enter fullscreen mode Exit fullscreen mode

首先,我们需要编辑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();


Enter fullscreen mode Exit fullscreen mode

我们已将其更改NestFactory.createNestFactory.createMicroservice。这将告诉 Nest 此应用现在是一个微服务。我们现在也有了一个配置 JSON 文件。我们需要告诉 Nest 我们想要使用哪种传输方式。TCP是最简单的,不需要任何额外配置。我们还可以使用RedisRabbitMQ等等。如果大家对本文感兴趣,我可以更详细地讲解这个主题。我们还需要将端口添加到配置 JSON 文件中。

我们需要编辑该应用/服务/微服务中的第二个文件是apps/blog/src/app.controller.ts

我们需要改变



  @Get()
  getHello(): string {
    return this.appService.getHello();
  }


Enter fullscreen mode Exit fullscreen mode



  @MessagePattern('getHello')
  getHello(name: string): string {
    return this.appService.getHello(name);
  }


Enter fullscreen mode Exit fullscreen mode

现在我们不再使用 http 动词了,但是MessagePattern……通过这个'getHello'名称,我们之后可以调用该函数。

apps/blog/src/app.service.ts
我们需要修改的第三个文件是……



@Injectable()
export class AppService {
  getHello(): string {
    return 'Hello World!';
  }
}


Enter fullscreen mode Exit fullscreen mode



@Injectable()
export class AppService {
  getHello(name: string): string {
    return `Hello ${name}!`;
  }
}


Enter fullscreen mode Exit fullscreen mode

这样,getHello 消息就可以接受一个字符串,以便我们能够返回名称。
好了!我们的blog微服务就完成了。

在我们的lampeweb应用程序中,我们需要修改以下 文件apps/lampeweb/src/app.service.ts



import { Injectable } from '@nestjs/common';

@Injectable()
export class AppService {
  getHello(): string {
    return 'Hello World!';
  }
}



Enter fullscreen mode Exit fullscreen mode



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();
  }
}



Enter fullscreen mode Exit fullscreen mode

好的,看起来内容有点多!我们添加了一个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();
  }
}


Enter fullscreen mode Exit fullscreen mode



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



Enter fullscreen mode Exit fullscreen mode

变化不大,只是我们现在期望 Promise 被解析为一个字符串。

好了!
现在需要重启这两个服务:



nest start
#and
nest start blog


Enter fullscreen mode Exit fullscreen mode

如果需要,您还可以将该--watch标志添加到这两个命令中,以便 Nest 每次保存时都会重建服务。

现在我们只需要打开浏览器并访问http://localhost:3000/

您现在应该看到以下内容
替代文字

希望你喜欢这篇文章!如果你想看到后续内容,请评论、点赞和分享。这样我就知道你对这类内容感兴趣了!

👋打个招呼! Instagram | Twitter | LinkedIn | Medium | Twitch | YouTube

文章来源:https://dev.to/lampewebdev/monorepo-and-microservice-setup-in-nest-js-41n4