库
库
许多应用程序需要解决相同的通用问题,或在多个不同的上下文中重用模块化组件。Nest 有几种方法来解决这个问题,但每种方法都在不同的层面上工作,以帮助满足不同的架构和组织目标。
Nest 模块 对于提供执行上下文很有用,它能够在单个应用程序内共享组件。模块也可以与 npm 打包,创建可重用的库,可以安装在不同的项目中。这可以是分发可配置、可重用库的有效方式,这些库可以被不同的、松散连接或无关联的组织使用(例如,通过分发/安装第三方库)。
对于在紧密组织的团队内共享代码(例如,在公司/项目边界内),使用更轻量级的方法来共享组件可能很有用。Monorepos 作为一种构造出现来实现这一点,在 monorepo 中,库 提供了一种简单、轻量级的代码共享方式。在 Nest monorepo 中,使用库可以轻松组装共享组件的应用程序。实际上,这鼓励了单体应用程序的分解和开发过程,专注于构建和组合模块化组件。
Nest 库
Nest 库是一个 Nest 项目,与应用程序的不同之处在于它不能独立运行。库必须被导入到包含的应用程序中,以便其代码能够执行。本节描述的内置库支持仅适用于 monorepos(标准模式项目可以使用 npm 包实现类似功能)。
例如,一个组织可能开发一个 AuthModule 来管理身份验证,通过实施管理所有内部应用程序的公司策略。与其为每个应用程序单独构建该模块,或使用 npm 物理打包代码并要求每个项目安装它,monorepo 可以将此模块定义为库。以这种方式组织时,库模块的所有消费者都可以看到 AuthModule 的最新版本,因为它已提交。这对于协调组件开发和组装以及简化端到端测试具有重大好处。
创建库
任何适合重用的功能都是作为库管理的候选者。决定什么应该是库,什么应该是应用程序的一部分,是一个架构设计决策。创建库不仅仅是简单地将代码从现有应用程序复制到新库中。当打包为库时,库代码必须与应用程序解耦。这可能需要更多的前期时间,并强制一些设计决策,这些决策在更紧密耦合的代码中可能不会面临。但是,当库可以用于在多个应用程序中实现更快速的应用程序组装时,这种额外的努力可以得到回报。
要开始创建库,请运行以下命令:
$ nest g library my-library
当您运行该命令时,library 原理图会提示您为库输入前缀(也称为别名):
What prefix would you like to use for the library (default: @app)?
这会在您的工作空间中创建一个名为 my-library 的新项目。
库类型项目,就像应用程序类型项目一样,使用原理图生成到命名文件夹中。库在 monorepo 根目录的 libs 文件夹下管理。Nest 在第一次创建库时创建 libs 文件夹。
为库生成的文件与为应用程序生成的文件略有不同。以下是执行上述命令后 libs 文件夹的内容:
libs/
└── my-library/
├── src/
│ ├── index.ts
│ ├── my-library.module.ts
│ └── my-library.service.ts
└── tsconfig.lib.json
nest-cli.json 文件将在 "projects" 键下为库添加一个新条目:
...
{
"my-library": {
"type": "library",
"root": "libs/my-library",
"entryFile": "index",
"sourceRoot": "libs/my-library/src",
"compilerOptions": {
"tsConfigPath": "libs/my-library/tsconfig.lib.json"
}
}
...
库和应用程序之间的 nest-cli.json 元数据有两个差异:
"type"属性设置为"library"而不是"application""entryFile"属性设置为"index"而不是"main"
这些差异是构建过程适当处理库的关键。例如,库通过 index.js 文件导出其函数。
与应用程序类型项目一样,库都有自己的 tsconfig.lib.json 文件,该文件扩展根(monorepo 范围)tsconfig.json 文件。如有必要,您可以修改此文件以提供特定于库的编译器选项。
您可以使用 CLI 命令构建库:
$ nest build my-library
使用库
有了自动生成的配置文件,使用库就很简单了。我们如何将 my-library 库中的 MyLibraryService 导入到 my-project 应用程序中?
首先,请注意使用库模块与使用任何其他 Nest 模块相同。monorepo 所做的是以一种方式管理路径,使得导入库和生成构建现在是透明的。要使用 MyLibraryService,我们需要导入其声明模块。我们可以修改 my-project/src/app.module.ts 如下以导入 MyLibraryModule。
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { MyLibraryModule } from '@app/my-library';
@Module({
imports: [MyLibraryModule],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
请注意上面我们在 ES 模块 import 行中使用了 @app 的路径别名,这是我们在上面的 nest g library 命令中提供的 prefix。在底层,Nest 通过 tsconfig 路径映射处理这个问题。添加库时,Nest 更新全局(monorepo)tsconfig.json 文件的 "paths" 键,如下所示:
"paths": {
"@app/my-library": [
"libs/my-library/src"
],
"@app/my-library/*": [
"libs/my-library/src/*"
]
}
简而言之,monorepo 和库功能的结合使得将库模块包含到应用程序中变得简单直观。
同样的机制使得构建和部署组合库的应用程序成为可能。一旦您导入了 MyLibraryModule,运行 nest build 会自动处理所有模块解析,并将应用程序与任何库依赖项一起打包以进行部署。monorepo 的默认编译器是 webpack,因此生成的分发文件是一个将所有转译的 JavaScript 文件打包到单个文件中的单个文件。您也可以切换到 tsc,如此处所述。