缓存
Turborepo 使用缓存来加速构建,确保您永远不会重复执行相同的工作。当您的任务可缓存时,Turborepo 将使用任务首次运行时的指纹从缓存中恢复任务结果。
Turborepo 的缓存在本地工作时可以显著节省时间 - 当启用远程缓存时更加强大,可以在整个团队和 CI 之间共享缓存。
在本页面中,您将学习:
Turborepo 假设您的任务是确定性的。如果一个任务能够在 Turborepo 感知的输入集合下产生不同的输出,缓存可能无法按预期工作。
命中您的第一个 Turborepo 缓存
您可以通过三个步骤尝试 Turborepo 的缓存行为:
创建一个新的 Turborepo 项目
使用 npx create-turbo@latest 并按照提示创建一个新的 Turborepo。
npx create-turbo@latest
首次运行构建
如果您已经全局安装了 turbo,请在您的仓库中运行 turbo build。
或者,您可以使用包管理器运行 package.json 中的 build 脚本。
pnpm run build
yarn build
npm run build
bun run build
这将导致缓存未命中,因为您从未在此仓库中使用此输入集合运行过 turbo。输入被转换为哈希,用于在本地文件系统缓存或远程缓存中检查。
命中缓存
再次运行 turbo build。您将看到类似这样的消息:
turbo 运行的结果,由于缓存命中,任务在极短时间内(如 116 毫秒)完成。因为输入的指纹已经在缓存中,所以没有理由再次从零开始重建您的应用程序。您可以从缓存中恢复之前构建的结果,节省资源和时间。
远程缓存
Turborepo 将任务结果存储在您机器上的 .turbo/cache 目录中。但是,您可以通过与团队成员和 CI 共享此缓存来使整个组织更加高效。
要了解更多关于远程缓存及其优势的信息,请访问远程缓存页面。
启用远程缓存
首先,使用您的远程缓存提供商进行身份验证:
npx turbo login
然后,将您机器上的仓库链接到远程缓存:
npx turbo link
现在,当您运行任务时,Turborepo 将自动将任务的输出发送到远程缓存。如果您在另一台也已通过远程缓存身份验证的机器上运行相同的任务,它将在首次运行任务时命中缓存。
有关如何将 CI 机器连接到远程缓存的信息,请访问构建 CI 指南。
默认情况下,Turborepo 使用 Vercel 远程缓存,无需配置。如果您想使用不同的远程缓存,请访问远程缓存 API 文档
什么会被缓存?
Turborepo 缓存两种类型的输出:任务输出和日志。
任务输出
Turborepo 缓存在 turbo.json 的 outputs 键中定义的任务文件输出。当缓存命中时,Turborepo 将从缓存中恢复文件。
outputs 键是可选的,请参阅 API 参考了解 Turborepo 在这种情况下的行为。
如果您没有为任务声明文件输出,Turborepo 将不会缓存它们。这对某些任务(如 linter)可能是可以的 - 但许多任务会产生您希望被缓存的文件。
如果您在命中缓存时遇到文件不可用的错误,请确保您已为任务定义了输出。
日志
Turborepo 始终捕获任务的终端输出,将这些日志从任务首次运行时恢复到您的终端。
您可以使用 --output-logs 标志或 outputLogs 配置选项配置重放日志的详细程度。
任务输入
输入由 Turborepo 进行哈希处理,为任务运行创建"指纹"。当"指纹"匹配时,运行任务将命中缓存。
在底层,Turborepo 创建两个哈希:全局哈希和任务哈希。如果任一哈希发生变化,任务将未命中缓存。
全局哈希输入
| 输入 | 示例 |
|---|---|
从根 turbo.json 和包 turbo.json 解析的任务定义 | 在根 turbo.json 或包配置中更改 outputs |
| 影响工作区根的锁文件更改 | 在根 package.json 中更新依赖项将导致所有任务未命中缓存 |
globalDependencies 文件内容 | 当 ./.env 在 globalDependencies 中列出时更改它将导致所有任务未命中缓存 |
globalEnv 中列出的变量值 | 当 GITHUB_TOKEN 在 globalEnv 中列出时更改其值 |
| 影响任务运行时的标志值 | 使用影响行为的标志,如 --cache-dir、--framework-inference 或 --env-mode |
| 任意传递参数 | turbo build -- --arg=value 与 turbo build 或 turbo build -- --arg=diff 相比将未命中缓存 |
包哈希输入
| 输入 | 示例 |
|---|---|
| 包配置更改 | 更改包的 turbo.json |
| 影响包的锁文件更改 | 在包的 package.json 中更新依赖项 |
包的 package.json 更改 | 在包的 package.json 中更新 name 字段 |
| 源代码控制中的文件更改 | 在 src/index.ts 中编写新代码 |
故障排除
使用试运行
Turborepo 有一个 --dry 标志,可用于查看如果您运行任务会发生什么,而无需实际运行它。这对于调试缓存问题很有用,当您不确定正在运行哪些任务时。
有关更多详细信息,请访问 --dry API 参考。
使用运行摘要
Turborepo 有一个 --summarize 标志,可用于获取任务的所有输入、输出等的概览。比较两个摘要将显示为什么两个任务的哈希不同。这对以下情况很有用:
- 调试输入:Turborepo 中的任务有许多输入。如果任务在您期望命中时未命中缓存,您可以使用运行摘要来检查哪些输入与您未预期的不同。
- 调试输出:如果缓存命中没有恢复您期望的文件,运行摘要可以帮助您了解从缓存中恢复了哪些输出。
虽然没有 Turborepo 原生的运行摘要 UI 查看器,但如果您想将运行摘要作为 Web 视图查看,我们鼓励您使用社区构建的 https://turbo.nullvoxpopuli.com。
关闭缓存
有时,您可能不希望将任务的输出写入缓存。这可以使用 "cache": false 为任务永久设置,或使用 --cache <options> 标志为整个运行设置。
覆盖缓存
如果您想强制 turbo 重新执行已缓存的任务,请使用 --force 标志。请注意,这会禁用读取缓存,而不是写入。
缓存任务比执行任务慢
可能会创建缓存最终比不缓存更慢的场景。这些情况很少见,但一些示例包括:
- 执行极快的任务:如果任务的执行速度比到远程缓存的网络往返更快,您应该考虑不缓存该任务。
- 输出资产巨大的任务:可能创建一个如此大的工件,以至于上传或下载它的时间超过重新生成它的时间,比如完整的 Docker 容器。在这些情况下,您应该考虑不缓存该任务。
- 具有自己缓存的脚本:一些任务有自己的内部缓存行为。在这些情况下,配置可能很快变得复杂,使 Turborepo 的缓存和应用程序缓存协同工作。
虽然这些情况很少见,但请确保测试项目的行为,以确定在特定位置禁用缓存是否提供性能优势。
下一步
现在您已经了解了 Turborepo 的缓存如何使您的仓库更快,让我们看看如何在 Turborepo 中开发应用程序和库。