-

Turborepo 简介

Monorepos 有很多优势,但它们难以扩展。每个工作区都有自己的测试套件、自己的 linting 和构建过程。单个 monorepo 可能有数千个任务要执行。

+

Turborepo 简介

+

Monorepos 有很多优势,但它们难以扩展。每个工作区都有自己的测试套件、自己的 linting 和构建过程。单个 monorepo 可能有数千个任务要执行。

Turborepo 是一个专为 JavaScript 和 TypeScript 代码库设计的构建系统,旨在优化 monorepos 和 single-package workspace 中的任务。它通过远程缓存(remote caching)和高效的任务调度(task scheduling)来解决 monorepos 中的扩展问题。Turborepo 也可以增量部署(adopted incrementally),并与各种包管理器配合使用。

turbo 基于 workspace 构建,workspaces 是 JavaScript 生态系统中包管理器的一项功能,允许将多个包分组到一个存储库中:

-

Workspace

在 JavaScript 中,Workspace 是指仓库中的特定实体,可以是单个包或包的集合。
包管理器的 root lock 文件(例如 pnpm-lock.yaml)以及任何其他配置都位于 Wrokspace 的根目录。在 Monorepo 中可以有多个工作区,每个工作区位于存储库的子目录中。

-

Single-package workspace

只有一个独立包的工作区,在工作区根目录下有一个 package.json 文件。

-

Multi-package workspace

包含多个包的工作区,包含多个 package.json 文件,其中一个位于工作区根目录中用于全局配置,其他位于每个包目录中。

+

Workspace

+

在 JavaScript 中,Workspace 是指仓库中的特定实体,可以是单个包或包的集合。
+包管理器的 root lock 文件(例如 pnpm-lock.yaml)以及任何其他配置都位于 Wrokspace 的根目录。在 Monorepo 中可以有多个工作区,每个工作区位于存储库的子目录中。

+

Single-package workspace

+

只有一个独立包的工作区,在工作区根目录下有一个 package.json 文件。

+

Multi-package workspace

+

包含多个包的工作区,包含多个 package.json 文件,其中一个位于工作区根目录中用于全局配置,其他位于每个包目录中。

这种类型的工作区通常称为 monorepo


以 npm 为例,turbo 会初始化一个这样的目录结构使其成为有效的 workspace:

1
2
3
4
5
6
7
8
9
10
|- package.json
|- package-lock.json
|- turbo.json
|- apps
|-- docs
|--- package.json
|-- web
|--- package.json
|- packages
|--- ui
-

一个 “有效的” turbo 项目至少要有:

例如,在根目录的 package.json 中配置:

1
2
3
4
5
6
{
"workspaces": [
"apps/*",
"packages/*"
]
}
-

那么 apps 或 packages 目录中有 package.json 的每个目录都将被视为一个包。

注意:Turborepo 不支持嵌套包,例如 apps/ 或 packages/ 这种,将一个包放在apps/a 并将另一个包放在 apps/a/b 的结构将导致错误。

@@ -227,10 +230,10 @@

根目录的 package.json 是 workspace 的基础,常见的配置:

1
2
3
4
5
6
7
8
9
10
11
12
{
"private": true,
"scripts": {
"build": "turbo run build",
"dev": "turbo run dev",
"lint": "turbo run lint"
},
"devDependencies": {
"turbo": "latest"
},
"packageManager": "npm@10.0.0"
}
-

而根目录的 turbo.json 用于配置 turbo 的行为。那些 lock 文件是包管理器和 turbo 用于 reproducible 的关键。此外,Turborepo 还利用它们分析工作区中内部包之间的依赖关系。


-

包中的 package.json

name 字段用于标识包。它在 workspace 中应该是唯一的。

+

包中的 package.json

+

name 字段用于标识包。它在 workspace 中应该是唯一的。

最佳做法是为内部包使用命名空间前缀,以避免与 npm 注册表上的其他包发生冲突。例如,如果组织名为 clin,则可以将包命名为 @clin/package-name。

@@ -238,10 +241,8 @@

exports 字段用于指定要使用该包的其他包的入口点。如果要在另一个包中使用一个包中的代码,将从该入口点导入。

例如,如果有一个 @repo/math 包,则可以这么写 exports 字段:

1
2
3
4
5
6
7
{
"exports": {
".": "./dist/constants.ts",
"./add": "./dist/add.ts",
"./subtract": "./dist/subtract.ts"
}
}
-

然后就可以从 @repo/math 包中导入 add 和 subtract 函数了:

1
2
3
import { GRAVITATIONAL_CONSTANT, SPEED_OF_LIGHT } from '@repo/math';
import { add } from '@repo/math/add';
import { subtract } from '@repo/math/subtract';
-

以这种方式使用导出有三个主要好处: