创建内部包
内部包 是工作区的构建块,为您提供了在整个代码库中共享代码和功能的强大方式。Turborepo 会使用 package.json 中的依赖关系自动理解内部包之间的关系,在底层创建一个包图来优化您的代码库工作流程。

让我们使用包的解剖部分的指导和编译包模式,创建您的第一个内部包来在代码库中共享数学工具。在下面的步骤中,我们假设您已经使用 create-turbo 创建了新的代码库或正在使用类似结构的代码库。
1. 创建空目录
您需要一个目录来放置包。让我们在 ./packages/math 创建一个。
package.json
turbo.json
apps/
packages/
math/ (新建)
ui/
package.json
eslint-config/
package.json
typescript-config/
package.json
2. 添加 package.json
接下来,为包创建 package.json。通过添加此文件,您将满足内部包的两个要求,使其可被 Turborepo 和工作区的其余部分发现。
package.json 中的 name 字段决定了如何在整个工作区中导入您的包。您在这里选择的名称(例如 @repo/math)正是其他包导入它的方式(例如 import { add } from '@repo/math/add')。
{
"name": "@repo/math",
"type": "module",
"scripts": {
"dev": "tsc --watch",
"build": "tsc"
},
"exports": {
"./add": {
"types": "./src/add.ts",
"default": "./dist/add.js"
},
"./subtract": {
"types": "./src/subtract.ts",
"default": "./dist/subtract.js"
}
},
"devDependencies": {
"@repo/typescript-config": "workspace:*",
"typescript": "latest"
}
}
{
"name": "@repo/math",
"type": "module",
"scripts": {
"dev": "tsc --watch",
"build": "tsc"
},
"exports": {
"./add": {
"types": "./src/add.ts",
"default": "./dist/add.js"
},
"./subtract": {
"types": "./src/subtract.ts",
"default": "./dist/subtract.js"
}
},
"devDependencies": {
"@repo/typescript-config": "workspace:*",
"typescript": "latest"
}
}
{
"name": "@repo/math",
"type": "module",
"scripts": {
"dev": "tsc --watch",
"build": "tsc"
},
"exports": {
"./add": {
"types": "./src/add.ts",
"default": "./dist/add.js"
},
"./subtract": {
"types": "./src/subtract.ts",
"default": "./dist/subtract.js"
}
},
"devDependencies": {
"@repo/typescript-config": "*",
"typescript": "latest"
}
}
{
"name": "@repo/math",
"type": "module",
"scripts": {
"dev": "tsc --watch",
"build": "tsc"
},
"exports": {
"./add": {
"types": "./src/add.ts",
"default": "./dist/add.js"
},
"./subtract": {
"types": "./src/subtract.ts",
"default": "./dist/subtract.js"
}
},
"devDependencies": {
"@repo/typescript-config": "workspace:*",
"typescript": "latest"
}
}
让我们逐一分解这个 package.json:
name:这是包发现的关键的字段。值@repo/math成为整个工作区中导入语句使用的确切标识符。如果您更改此名称,必须相应地更新所有导入语句。scripts:dev和build脚本使用 TypeScript 编译器编译包。dev脚本将监视源代码的更改并自动重新编译包。devDependencies:typescript和@repo/typescript-config是devDependencies,因此您可以在@repo/math包中使用这些包。在实际的包中,您可能会有更多的devDependencies和dependencies- 但现在我们可以保持简单。exports:为包定义多个入口点,以便可以在其他包中使用(import { add } from '@repo/math/add')。
值得注意的是,这个 package.json 声明了一个内部包 @repo/typescript-config 作为依赖项。Turborepo 将识别 @repo/math 作为 @repo/typescript-config 的依赖者,用于排序您的任务。
3. 添加 tsconfig.json
通过在包的根目录添加 tsconfig.json 文件来指定此包的 TypeScript 配置。TypeScript 有一个 extends 键,允许您在整个代码库中使用基础配置,并根据需要使用不同的选项进行覆盖。
{
"extends": "@repo/typescript-config/base.json",
"compilerOptions": {
"outDir": "dist",
"rootDir": "src"
},
"include": ["src"],
"exclude": ["node_modules", "dist"]
}
您在这里做了四件重要的事情:
- 位于
./packages/typescript-config中的@repo/typescript-config/base.json配置包含您需要的所有配置,因此您从中扩展。 compilerOptions中的outDir键告诉 TypeScript 将编译输出放在哪里。它与您在package.json中的exports中指定的目录匹配。compilerOptions中的rootDir键确保outDir中的输出使用与src目录相同的结构。include和exclude键不会从基础配置继承,根据 TypeScript 规范,因此您在这里包含了它们。
关于 TypeScript 配置还有很多要学习的,但这是现在开始的好地方。如果您想了解更多,请访问 TypeScript 官方文档。
4. 添加包含源代码的 src 目录
您现在可以为您的包编写一些代码。在 src 目录中创建两个文件:
export const add = (a: number, b: number) => a + b;
export const subtract = (a: number, b: number) => a - b;
这些文件映射到当您稍后运行 turbo build 时 tsc 将创建的输出。
5. 将包添加到应用程序
您已准备好在应用程序中使用新包。让我们将其添加到 web 应用程序。
{
"dependencies": {
+ "@repo/math": "workspace:*",
"next": "latest",
"react": "latest",
"react-dom": "latest"
}
}
{
"dependencies": {
+ "@repo/math": "*",
"next": "latest",
"react": "latest",
"react-dom": "latest"
}
}
{
"dependencies": {
+ "@repo/math": "*",
"next": "latest",
"react": "latest",
"react-dom": "latest"
}
}
{
"dependencies": {
+ "@repo/math": "workspace:*",
"next": "latest",
"react": "latest",
"react-dom": "latest"
}
}
您刚刚更改了代码库中的依赖项。确保运行包管理器的安装命令来更新您的锁定文件。
@repo/math 现在在 web 应用程序中可用,您可以在代码中使用它:
import { add } from '@repo/math/add';
function Page() {
return <div>{add(1, 2)}</div>;
}
export default Page;
6. 编辑 turbo.json
将新的 @repo/math 库的构建产物添加到 turbo.json 中 build 任务的 outputs 中。这确保其构建输出将被 Turborepo 缓存,因此当您开始运行构建时可以立即恢复它们。
{
"tasks": {
"build": {
"dependsOn": ["^build"],
"outputs": [".next/**", "!.next/cache/**", "dist/**"]
}
}
}
7. 运行 turbo build
如果您已经全局安装了 turbo,请在工作区根目录的终端中运行 turbo build。您也可以使用包管理器运行 package.json 中的 build 脚本,这将使用 turbo run build。
@repo/math 包在 web 应用程序构建之前构建,以便当 web 应用程序打包时,./packages/math/dist 中的运行时代码可用。
您可以再次运行 turbo build 来查看您的 web 应用程序在毫秒内重建。我们将在缓存指南中详细讨论这一点。
内部包的最佳实践
每个包一个"目的"
当您创建内部包时,建议创建具有单一"目的"的包。这不是严格的科学或规则,而是根据您的代码库、规模、组织、团队需求等的最佳实践。这种策略有几个优点:
- 更容易理解:随着代码库的扩展,在代码库中工作的开发人员将更容易找到他们需要的代码。
- 减少每个包的依赖项:每个包使用更少的依赖项使得 Turborepo 可以更有效地修剪包图的依赖项。
一些示例包括:
@repo/ui:包含所有共享 UI 组件的包@repo/tool-specific-config:用于管理特定工具配置的包@repo/graphs:用于创建和操作图形数据的特定领域库
应用程序包不包含共享代码
当您创建应用程序包时,最好避免在这些包中放置共享代码。相反,您应该为共享代码创建一个单独的包,并让应用程序包依赖于该包。
此外,应用程序包不应安装到其他包中。相反,它们应该被视为包图的入口点。
这个规则有罕见的例外。
下一步
有了新的内部包,您可以开始配置任务。