创建内部包

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

Visual representation of a Package Graph in a Turborepo.

让我们按照 包的解剖结构 部分和 编译包 模式中的指导,创建你的第一个内部包,以在你的仓库中共享数学实用程序。在下面的步骤中,我们假设你已经 使用 create-turbo 创建了一个新仓库,或者正在使用结构类似的仓库。

创建一个空目录

你需要一个目录来放置包。让我们在 ./packages/math 创建一个。

package.json
turbo.json

添加 package.json

接下来,为包创建 package.json。通过添加此文件,你将满足 内部包的两个要求,使其可被 Turborepo 和你工作区的其余部分发现

./packages/math/package.json
{
  "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

  • scripts: devbuild 脚本使用 TypeScript 编译器 编译包。dev 脚本将监视源代码的更改并自动重新编译包。
  • devDependencies: typescript@repo/typescript-configdevDependencies,因此你可以在 @repo/math 包中使用这些包。在一个实际的包中,你可能会有更多的 devDependenciesdependencies - 但现在我们可以保持简单。
  • exports: 为包定义多个入口点,以便它可以在其他包中使用 (import { add } from '@repo/math')。

值得注意的是,此 package.json 声明了一个内部包 @repo/typescript-config 作为依赖项。Turborepo 将识别 @repo/math 作为 @repo/typescript-config 的依赖项,以便对你的任务进行排序。

添加 tsconfig.json

通过将 tsconfig.json 文件添加到包的根目录,为此包指定 TypeScript 配置。TypeScript 具有 extends,允许你在整个仓库中使用基本配置,并根据需要使用不同的选项覆盖它。

./packages/math/tsconfig.json
{
  "extends": "@repo/typescript-config/base.json",
  "compilerOptions": {
    "outDir": "dist",
    "rootDir": "src"
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}

你在这里完成了四件重要的事情

关于 TypeScript 配置还有很多要学习的内容,但这对于现在来说是一个好的开始。如果你想了解更多信息,请访问 官方 TypeScript 文档我们的 TypeScript 指南

添加带有源代码的 src 目录

你现在可以为你的包编写一些代码了。在 src 目录中创建两个文件

./packages/math/src/add.ts
export const add = (a: number, b: number) => a + b;

这些文件映射到当你稍后运行 turbo buildtsc 将创建的输出。

将包添加到应用程序

你已准备好在应用程序中使用你的新包。让我们将其添加到 web 应用程序。

apps/web/package.json
  "dependencies": {
+   "@repo/math": "workspace:*",
    "next": "latest",
    "react": "latest",
    "react-dom": "latest"
  },

你刚刚更改了仓库中的依赖项。请务必运行你的包管理器的安装命令以更新你的 lockfile。

@repo/math 现在在 web 应用程序中可用,你可以在你的代码中使用它

apps/web/src/app/page.tsx
import { add } from '@repo/math/add';
 
function Page() {
  return <div>{add(1, 2)}</div>;
}
 
export default Page;

编辑 turbo.json

将新 @repo/math 库的 artifacts 添加到 turbo.jsonbuild 任务的 outputs。这确保了其构建输出将被 Turborepo 缓存,以便它们可以在你开始运行构建时立即恢复。

Turborepo logo
./turbo.json
{
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": [".next/**", "!.next/cache/**", "dist/**"]
    }
  }
}

运行 turbo build

如果你已经 全局安装了 turbo,请在你的工作区根目录的终端中运行 turbo build。你也可以使用你的包管理器从 package.json 运行 build 脚本,这将使用 turbo run build

@repo/math 包在 web 应用程序构建之前构建,以便 ./packages/math/dist 中的运行时代码在 web 应用程序捆绑时可用。

你可以再次运行 turbo build 以查看你的 web 应用程序在毫秒内重建。我们将在 缓存指南 中详细讨论这一点。

内部包的最佳实践

每个包一个“目的”

当你创建内部包时,建议创建具有单一“目的”的包。这不是严格的科学或规则,而是一个最佳实践,取决于你的仓库、你的规模、你的组织、你的团队的需求等等。这种策略有几个优点

  • 更易于理解:随着仓库规模的扩大,在仓库中工作的开发人员将更容易找到他们需要的代码。
  • 减少每个包的依赖项:每个包使用更少的依赖项使得 Turborepo 可以更有效地 修剪你的包图的依赖项

一些例子包括

  • @repo/ui:一个包含所有共享 UI 组件的包
  • @repo/tool-specific-config:一个用于管理特定工具配置的包
  • @repo/graphs:一个用于创建和操作图形数据的特定领域库

应用程序包不包含共享代码

当你创建 应用程序包 时,最好避免将共享代码放在这些包中。相反,你应该为共享代码创建一个单独的包,并让应用程序包依赖于该包。

此外,应用程序包不应安装到其他包中。相反,它们应该被视为你的 包图 的入口点。

须知: 

对于此规则,存在 罕见的例外情况

下一步

有了新的内部包,你可以开始 配置任务