Turborepo 缓存机制全解析:从缓存方程到 global.inputs 的哈希深入指南
Turborepo 缓存机制全解析从缓存方程到 global.inputs 的哈希深入指南【免费下载链接】turboBuild system optimized for JavaScript and TypeScript, written in Rust项目地址: https://gitcode.com/gh_mirrors/tu/turboTurborepo 是一个用 Rust 编写的 JavaScript/TypeScript 构建系统优化工具其最核心的设计原则是绝不重复做同样的工作never do the same work twice。本文以 skills/turborepo/references/caching/RULE.md 为骨架结合仓库内 Rust 源码turborepo-hash、turborepo-cache与集成测试global_inputs_test.rs系统讲解 Turborepo 缓存的工作机制缓存方程如何计算、全局哈希与任务哈希的输入有哪些、global.inputs如何改变哈希方程、缓存中存储什么、缓存放哪里、命中后如何恢复。读完本文你将能准确判断什么改动会让缓存失效这一 Turborepo 使用中最关键的问题并能利用futureFlags.globalConfiguration精确控制全局文件的缓存粒度。缓存方程fingerprint(inputs) → stored outputsTurborepo 缓存机制可以用一条方程概括fingerprint(inputs) → stored outputs如果某次任务的输入与上次完全一致哈希相同Turborepo 就直接从缓存恢复输出而不重新执行任务。这里的输入是一组经过哈希计算得到的指纹fingerprint输出则是构建产物与日志。缓存键由两层哈希共同决定task cache key hash(global hash, task hash)global hash全局哈希影响仓库中所有任务的公共输入。task hash任务哈希只影响某个具体任务的输入。只有两层哈希都未变化缓存才会命中。这一方程在源码中有直接对应crates/turborepo-hash/src/lib.rs中定义了GlobalHashable承载全局哈希输入与TaskHashable承载任务哈希输入两个结构体其中TaskHashable明确包含global_hash字段任务哈希计算时会把全局哈希一并卷入。全局哈希输入影响所有任务的公共因子以下输入会进入全局哈希任何一项变化都会使仓库内所有任务的缓存失效锁文件package-lock.json、yarn.lock、pnpm-lock.yaml、bun.lock。注意二进制格式的bun.lockb不受支持需要先运行bun install --save-text-lockfile将其转换为文本格式。globalDependencies中列出的文件使用globalConfiguration时改用global.inputs见下文。globalEnv中列出的环境变量使用globalConfiguration时改用global.env。turbo.json配置本身。配置示例{ globalDependencies: [.env, tsconfig.base.json], globalEnv: [CI, NODE_ENV] }从源码看锁文件并非直接以文件哈希进入全局哈希而是经过结构化处理crates/turborepo-hash/src/lib.rs中LockFilePackages会提取锁文件中每个包的key与version再通过turborepo_lockfile_hash做规范化序列化。这意味着锁文件内容的无关变化如注释、格式调整不会影响缓存只有包集合或版本变化才真正触发全局失效。GlobalHashable结构体还揭示了全局哈希的其他输入包括global_file_hash_map全局依赖文件哈希映射、root_external_dependencies_hash根外部依赖哈希、root_internal_dependencies_hash根内部依赖哈希、enginesNode 等引擎版本、env与resolved_env_vars、framework_inference框架推断开关以及global_configuration是否启用 globalConfiguration 模式。任务哈希输入决定单个任务缓存的因子以下输入会进入单个任务的任务哈希包内所有文件除非被inputs过滤。package.json内容。任务env键中列出的环境变量。任务配置本身命令command、outputs、依赖关系。依赖任务的哈希由dependsOn决定包括^build这类依赖包任务。使用futureFlags.globalConfiguration时global.inputs中的文件也会并入任务输入见下一节。配置示例{ tasks: { build: { dependsOn: [^build], inputs: [src/**, package.json, tsconfig.json], env: [API_URL] } } }源码中TaskHashable结构体逐一对应了这些输入task_dependency_hashes依赖任务哈希、hash_of_files包内文件哈希、external_deps_hash外部依赖哈希、outputs、pass_through_args、env、resolved_env_vars、command_override等。值得注意的细节是任务的实际执行命令command override也参与哈希——从源码注释看改变任务实际运行的命令必须使其缓存结果失效这保证了改动命令不会命中陈旧缓存。global.inputs如何改变哈希方程当在turbo.json中启用futureFlags.globalConfiguration后global.inputs的行为与globalDependencies有根本性差异global.inputs中的文件不再进入全局哈希而是被前置到每个任务的inputs中折叠进任务哈希。使用globalDependencies默认模式task cache key hash(global hash, task hash) ↑ 包含 globalDependencies 文件哈希在这种模式下修改globalDependencies中的任何文件都会使每一个任务失效无论任务级inputs如何设置任务都无法选择退出。集成测试 crates/turborepo/tests/global_inputs_test.rs 中的test_global_dependencies_cannot_be_excluded_by_task_inputs正是验证了这一点测试注释明确指出即使任务用取反 glob 明确排除了该文件取反也没有效果因为文件位于全局哈希而非任务输入中。使用global.inputsfutureFlags.globalConfiguration模式task cache key hash(global hash, task hash) ↑ 包含 global.inputs 文件哈希与任务 inputs 合并global.inputs的文件会合并进每个任务的输入 glob。这意味着任务可以用取反 glob 排除特定全局文件inputs: [$TURBO_DEFAULT$, !$TURBO_ROOT$/tsconfig.json]全局哈希变小它仍包含锁文件、engines、global.env等但不再包含global.inputs文件的文件哈希。任务哈希正确地把全局输入文件哈希与任务自身输入合并在一起。完整配置示例{ futureFlags: { globalConfiguration: true }, global: { inputs: [tsconfig.json, .env] }, tasks: { build: { outputs: [dist/**] }, lint: { inputs: [$TURBO_DEFAULT$, !$TURBO_ROOT$/tsconfig.json] } } }在这个例子中修改tsconfig.json会使build失效它位于该任务输入中但不会使lint失效它被显式排除。而在globalDependencies模式下两者都会被失效。这段行为差异同样有集成测试佐证global_inputs_test.rs中的test_global_inputs_can_be_excluded_and_affect_tasks验证了启用globalConfiguration后排除config.txt的任务app-b在第三次构建时命中缓存输出cache hit而未排除的任务app-a则正常失效重跑。这里涉及两个魔法变量说明如下$TURBO_DEFAULT$展开为包内全部文件的默认输入集合相当于未写inputs时的默认行为在自定义inputs时用它作为基线再叠加增删。$TURBO_ROOT$指向 monorepo 仓库根目录的绝对路径用于书写!$TURBO_ROOT$/tsconfig.json这类跨包取反表达式。缓存中存储什么Turborepo 为每个任务缓存两类内容文件输出outputs中指定的文件/目录。任务日志stdout/stderr供缓存命中时重放。{ tasks: { build: { outputs: [dist/**, .next/**] } } }关键要点缓存是内容寻址的基于输入哈希而非时间戳。空outputs数组表示任务照常运行但什么都不缓存。没有outputs键的任务不缓存任何东西如需显式表达用outputs: []。本地缓存位置默认情况下本地缓存存放在仓库根目录下.turbo/cache/ ├── hash1.tar.zst # 压缩后的输出 ├── hash2.tar.zst └── ...请务必将.turbo加入.gitignore避免缓存目录进入版本控制。源码层面本地缓存由crates/turborepo-cache/src/fs.rs中的FSCache实现fetch方法按{hash}.tar.zst拼接缓存路径并检查文件是否存在每个缓存归档还配有一个{hash}-manifest.json清单文件与-meta.json元数据记录 hash、duration、git sha 等。FSCache::new在初始化时通过create_dir_all确保缓存目录存在。整个 crate 的文档注释crates/turborepo-cache/src/lib.rs明确指出底层缓存产物是gzip 压缩的 tarball.tar.zst即 zstd 压缩的 tar 包。此外crates/turborepo-cache/src/cache_archive/目录下按职责拆分了create.rs归档写入、restore.rs归档恢复、restore_manifest.rs恢复清单等模块其中RestoreManifest支持快速路径校验若清单存在且磁盘上所有文件仍然匹配可跳过解压 tar 直接判定命中。缓存恢复流程缓存命中时Turborepo 依次执行解压归档输出到原始位置restore相关模块负责把 tar 中的文件恢复到各自路径。重放记录的 stdout/stderr日志。将任务标记为 cached在输出中显示FULL TURBO。从fs.rs的fetch实现还能看到一个性能优化细节恢复时若-manifest.json存在且磁盘上所有文件都仍然匹配manifest.validate_all(anchor)则完全跳过打开与解压 tar 的步骤——这就是缓存快速路径。示例流程从 cache miss 到 FULL TURBO# 第一次运行 - 执行 build并缓存结果 turbo build # → packages/ui: cache miss, executing... # → packages/web: cache miss, executing... # 第二次运行 - 输入未变从缓存恢复 turbo build # → packages/ui: cache hit, replaying output # → packages/web: cache hit, replaying output # → FULL TURBO关键要点速查缓存是内容寻址的基于输入哈希而不是时间戳。空outputs数组意味着任务会运行但不缓存任何东西。没有outputs键的任务同样不缓存如需显式表达请写outputs: []。任何输入变化都会使缓存失效——这是缓存正确性的基石。全局哈希与任务哈希共同决定缓存键task cache key hash(global hash, task hash)。globalDependencies模式下任务无法排除全局文件启用futureFlags.globalConfiguration后global.inputs会并入任务输入从而允许用取反 glob如!$TURBO_ROOT$/tsconfig.json精确控制失效范围。进一步阅读本文骨架文档skills/turborepo/references/caching/RULE.md缓存常见陷阱skills/turborepo/references/caching/gotchas.md远程缓存skills/turborepo/references/caching/remote-cache.md哈希实现crates/turborepo-hash/src/lib.rs全局哈希/任务哈希结构体与 Capn Proto 序列化缓存实现crates/turborepo-cache/src/fs.rs、crates/turborepo-cache/src/lib.rs、crates/turborepo-cache/src/cache_archive/缓存配置解析local:rw,remote:r等crates/turborepo-cache/src/config.rsglobal.inputs 行为验证测试crates/turborepo/tests/global_inputs_test.rs【免费下载链接】turboBuild system optimized for JavaScript and TypeScript, written in Rust项目地址: https://gitcode.com/gh_mirrors/tu/turbo创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

网盘直链下载工具完整教程:三步拿到直链,新手零门槛

网盘直链下载工具完整教程:三步拿到直链,新手零门槛

网盘直链下载工具完整教程:三步拿到直链,新手零门槛 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 ,支持 百度网盘 / 阿里云盘 / 中国移动云…

2026/9/20 21:14:28 阅读更多 →
enzyme ReactWrapper.closest(selector):向上遍历查找最近匹配祖先节点的权威指南

enzyme ReactWrapper.closest(selector):向上遍历查找最近匹配祖先节点的权威指南

测试前端 【免费下载链接】enzyme JavaScript Testing utilities for React 项目地址: https://gitcode.com/gh_mirrors/en/enzyme 点击查看 免费下载 导读 .closest(selector) 是 enzyme ReactWrapper(以及 ShallowWrapper)提供的祖先节点…

2026/9/20 21:14:28 阅读更多 →
Spark Connect Protobuf 定义:协议文件与 Python 桩代码生成全指南

Spark Connect Protobuf 定义:协议文件与 Python 桩代码生成全指南

Spark Connect Protobuf 定义:协议文件与 Python 桩代码生成全指南 【免费下载链接】spark Apache Spark - A unified analytics engine for large-scale data processing 项目地址: https://gitcode.com/gh_mirrors/sp/spark Spark Connect 是 Apache Spark…

2026/9/21 22:57:59 阅读更多 →

最新新闻

3个坑让仙台地图渲染崩盘?这份保姆级教程救你

3个坑让仙台地图渲染崩盘?这份保姆级教程救你

3个坑让仙台地图渲染崩盘?这份保姆级教程救你 上周给一个医疗SaaS项目做区域数据可视化,客户点名要集成“仙台地图”组件。我信心满满,结果第一版代码跑起来,控制台直接炸出一屏红字,StackTrace 长得像天书,滚动条都拉不到底。…

2026/9/22 1:02:19 阅读更多 →
3个新手避坑点:北京积分落户新政策源码级拆解与帧对比选型

3个新手避坑点:北京积分落户新政策源码级拆解与帧对比选型

3个新手避坑点:北京积分落户新政策源码级拆解与帧对比选型 看了一堆教程还是不会写项目?别怪自己笨,是你没搞懂底层逻辑。北京积分落户新政策的核心其实就是一本动态账本,很多新手在报名材料清单整理时栽跟头,不是因为材料不全,而是因为没看懂“加权逻…

2026/9/22 1:02:19 阅读更多 →
自动重拨最佳实践

自动重拨最佳实践

3个坑让你告别手动重拨:新手避坑指南 学会语法却不知怎么搭项目,是很多刚入行同学的通病。特别是处理网络不稳定场景时,盯着报错日志发呆,只会手动刷新页面。自动重拨机制看似简单,实则暗藏玄机,稍不留神就陷入死循环。 入口定位:为什么你需要它…

2026/9/22 1:02:19 阅读更多 →
商标宝注册全流程解析与避坑最佳实践

商标宝注册全流程解析与避坑最佳实践

商标宝注册全流程解析与避坑最佳实践 刚拿到商标宝查询结果,或者在提交注册时看到那一长串红色的 StackTrace 报错,是不是瞬间大脑宕机?很多人以为这是系统崩溃,其实是你的申请文件触发了审查系统的硬性拦截。别慌,这行干久了就知道,报错不…

2026/9/22 1:02:19 阅读更多 →
3个实战项目拆解ustcmail,彻底搞懂USTC邮件系统

3个实战项目拆解ustcmail,彻底搞懂USTC邮件系统

3个实战项目拆解ustcmail,彻底搞懂USTC邮件系统 看了一堆教程还是不会写项目?这是大多数应届生在准备大厂面试时的真实困境。你背了无数八股文,刷了上百道算法题,但一旦面试官问起“你做过什么实战项目”,你的大脑瞬间空白。特别是当涉及到…

2026/9/22 1:02:19 阅读更多 →
高速工具钢源码解析: 3步搞定版本API变更坑

高速工具钢源码解析: 3步搞定版本API变更坑

高速工具钢源码解析: 3步搞定版本API变更坑 版本升级后 API 全变了,这是转岗工程师最崩溃的瞬间。你刚把旧版逻辑跑通,新版文档却换了天,报错堆栈像天书。别慌,我们直接拆解 高速工具钢 相关的底层逻辑,通过 源码解析 找到不变的内核。…

2026/9/22 1:01:18 阅读更多 →

日新闻

3台商务办公笔记本实测:手写实现环境配置,告别卡半天

3台商务办公笔记本实测:手写实现环境配置,告别卡半天

3台商务办公笔记本实测:手写实现环境配置,告别卡半天 配置环境就卡半天?别怪机器慢,多半是你没选对工具链。在Java、Go或Python的项目现场, 手写实现…

2026/9/22 0:00:41 阅读更多 →
剑帝加点速查手册:3分钟搞懂核心逻辑

剑帝加点速查手册:3分钟搞懂核心逻辑

剑帝加点速查手册:3分钟搞懂核心逻辑 面试被问原理答不上来,是不是常态?别慌。很多开发者对着 GitHub 开源仓库里的代码发呆,看似简单实则暗藏玄机。今天这份【剑帝加点】速查手册,直接带你拆解核心实现,把面试必考的原理讲透。…

2026/9/22 0:00:41 阅读更多 →
手写实现图片压缩网站核心:搞定WebP转换与质量调优

手写实现图片压缩网站核心:搞定WebP转换与质量调优

手写实现图片压缩网站核心:搞定WebP转换与质量调优 复制来的代码跑不通不知道怎么调?别慌,这种“复制粘贴地狱”在开发圈太常见了。尤其是做 图片压缩网站…

2026/9/22 0:00:41 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/21 3:13:20 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/21 2:19:36 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/21 4:51:05 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/21 15:36:51 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/21 15:36:51 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/19 23:35:34 阅读更多 →