许多应用程序需要解决相同的一般问题,或在多个不同环境中重复使用模块化组件。 Nest 有几种解决此问题的方法,但每种方法都在不同的层次上工作,以有助于满足不同的架构和组织目标的方式解决问题。
Nest 模块 可用于提供执行上下文,从而允许在单个应用程序内共享组件。 模块还可以与 npm 一起打包,以创建可安装在不同项目中的可重复使用的库。 这是一种分发可配置、可重复使用的库的有效方法,这些库可由不同的、松散连接或无关联的组织使用(例如,通过分发/安装第三方库)。
对于在紧密组织的团体内共享代码(例如,在公司/项目边界内),采用更轻量级的方法来共享组件会很有用。 Monorepos 作为一种实现这一点的构造而出现,在 monorepo 中,库 提供了一种以简单、轻量级的方式共享代码的方法。在 Nest monorepo 中,使用库可以轻松组装共享组件的应用程序。事实上,这鼓励分解单片应用程序和开发流程,以专注于构建和组合模块化组件。
Nest 库
Nest 库是一个 Nest 项目,它与应用程序的不同之处在于它不能单独运行。必须将库导入包含应用程序才能执行其代码。本节中描述的对库的内置支持仅适用于 monorepos(标准模式项目可以使用 npm 包实现类似功能)。
例如,组织可以开发一个 AuthModule
,通过实施管理所有内部应用程序的公司策略来管理身份验证。monorepo 可以将此模块定义为库,而不是为每个应用程序单独构建该模块,或者使用 npm 物理打包代码并要求每个项目安装它。当以这种方式组织时,库模块的所有使用者都可以看到提交的 AuthModule
的最新版本。这对于协调组件开发和组装以及简化端到端测试具有重大好处。
创建库
任何适合重复使用的功能都可以作为库进行管理。决定什么应该是库,什么应该是应用程序的一部分,是一个架构设计决策。创建库不仅仅是将代码从现有应用程序复制到新库。当打包为库时,库代码必须与应用程序分离。这可能需要更多时间,并迫使您做出一些设计决策,而这些决策在更紧密耦合的代码中可能不会遇到。但是,当可以使用库来实现跨多个应用程序的更快速的应用程序组装时,这种额外的努力是值得的。
要开始创建库,请运行以下命令:
$ nest g library my-library
运行该命令时,library
原理图会提示您输入库的前缀(又称别名):
bash
您想为库使用什么前缀(默认:@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
使用库
有了自动生成的配置文件,使用库就很简单了。我们如何将MyLibraryService
从my-library
库导入到my-project
应用程序中?
首先,请注意,使用库模块与使用任何其他 Nest 模块相同。monorepo 所做的是以一种现在透明的方式管理路径,以便导入库和生成构建。要使用MyLibraryService
,我们需要导入其声明模块。我们可以按如下方式修改my-project/src/app.module.ts
以导入MyLibraryModule
。
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
键:
{
"paths": {
"@app/my-library": [
"libs/my-library/src"
],
"@app/my-library/*": [
"libs/my-library/src/*"
]
}
}
因此,简而言之,monorepo 和库功能的组合使得将库模块包含到应用程序中变得简单而直观。
同样的机制支持构建和部署组成库的应用程序。导入 MyLibraryModule
后,运行 nest build
会自动处理所有模块解析,并将应用程序与任何库依赖项捆绑在一起以进行部署。monorepo 的默认编译器是 webpack,因此生成的分发文件是一个文件,它将所有转译的 JavaScript 文件捆绑到一个文件中。您还可以按照此处 所述切换到 tsc
。