Libraries

导读

许多应用程序需要解决相同的一般问题,或在多个不同环境中重复使用模块化组件。 Nest 有几种解决此问题的方法,但每种方法都在不同的层次上工作,以有助于满足不同的架构和组织目标的方式解决问题。

Nest 模块 可用于提供执行上下文,从而允许在单个应用程序内共享组件。 模块还可以与 npm 一起打包,以创建可安装在不同项目中的可重复使用的库。 这是一种分发可配置、可重复使用的库的有效方法,这些库可由不同的、松散连接或无关联的组织使用(例如,通过分发/安装第三方库)。

对于在紧密组织的团体内共享代码(例如,在公司/项目边界内),采用更轻量级的方法来共享组件会很有用。 Monorepos 作为一种实现这一点的构造而出现,在 monorepo 中, 提供了一种以简单、轻量级的方式共享代码的方法。在 Nest monorepo 中,使用库可以轻松组装共享组件的应用程序。事实上,这鼓励分解单片应用程序和开发流程,以专注于构建和组合模块化组件。

Nest 库

Nest 库是一个 Nest 项目,它与应用程序的不同之处在于它不能单独运行。必须将库导入包含应用程序才能执行其代码。本节中描述的对库的内置支持仅适用于 monorepos(标准模式项目可以使用 npm 包实现类似功能)。

例如,组织可以开发一个 AuthModule,通过实施管理所有内部应用程序的公司策略来管理身份验证。monorepo 可以将此模块定义为库,而不是为每个应用程序单独构建该模块,或者使用 npm 物理打包代码并要求每个项目安装它。当以这种方式组织时,库模块的所有使用者都可以看到提交的 AuthModule 的最新版本。这对于协调组件开发和组装以及简化端到端测试具有重大好处。

创建库

任何适合重复使用的功能都可以作为库进行管理。决定什么应该是库,什么应该是应用程序的一部分,是一个架构设计决策。创建库不仅仅是将代码从现有应用程序复制到新库。当打包为库时,库代码必须与应用程序分离。这可能需要更多时间,并迫使您做出一些设计决策,而这些决策在更紧密耦合的代码中可能不会遇到。但是,当可以使用库来实现跨多个应用程序的更快速的应用程序组装时,这种额外的努力是值得的。

要开始创建库,请运行以下命令:

bash
$ nest g library my-library

运行该命令时,library原理图会提示您输入库的前缀(又称别名):

bash 您想为库使用什么前缀(默认:@app)? `

这会在您的工作区中创建一个名为my-library的新项目。 库类型的项目(如应用程序类型的项目)使用原理图生成到命名文件夹中。库在 monorepo 根目录的libs文件夹下进行管理。Nest 会在第一次创建库时创建libs文件夹。

为库生成的文件与为应用程序生成的文件略有不同。执行上述命令后,libs文件夹的内容如下:

bash
libs
 └─ my-library
  ├─ src
 ├─ index.ts
 ├─ my-library.module.ts
 └─ my-library.service.ts
  └─ tsconfig.lib.json

nest-cli.json 文件将在 "projects" 键下为库添加一个新条目:

json
{
  "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 命令构建库:

bash
$ nest build my-library

使用库

有了自动生成的配置文件,使用库就很简单了。我们如何将MyLibraryServicemy-library库导入到my-project应用程序中?

首先,请注意,使用库模块与使用任何其他 Nest 模块相同。monorepo 所做的是以一种现在透明的方式管理路径,以便导入库和生成构建。要使用MyLibraryService,我们需要导入其声明模块。我们可以按如下方式修改my-project/src/app.module.ts以导入MyLibraryModule

ts
import { Module } from '@nestjs/common'
import { MyLibraryModule } from '@app/my-library'
import { AppController } from './app.controller'
import { AppService } from './app.service'

@Module({
  imports: [MyLibraryModule],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

请注意,我们在 ES 模块import行中使用了@app路径别名,这是我们在上面的nest g library命令中提供的前缀。在幕后,Nest 通过 tsconfig 路径映射来处理这个问题。添加库时,Nest 会像这样更新全局(monorepo)tsconfig.json文件的paths键:

json
{
  "paths": {
    "@app/my-library": [
      "libs/my-library/src"
    ],
    "@app/my-library/*": [
      "libs/my-library/src/*"
    ]
  }
}

因此,简而言之,monorepo 和库功能的组合使得将库模块包含到应用程序中变得简单而直观。

同样的机制支持构建和部署组成库的应用程序。导入 MyLibraryModule 后,运行 nest build 会自动处理所有模块解析,并将应用程序与任何库依赖项捆绑在一起以进行部署。monorepo 的默认编译器是 webpack,因此生成的分发文件是一个文件,它将所有转译的 JavaScript 文件捆绑到一个文件中。您还可以按照此处 所述切换到 tsc