跳至主要内容
非官方测试版翻译

本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →

缓存工作原理

在执行任何任务前,Lerna 会计算其任务哈希值。只要该哈希值保持不变,任务运行的输出结果就保持不变。

以命令 lerna run test --scope=remixapp 为例,默认情况下其任务哈希包含:

  • remixapp 及其依赖项的所有源代码文件

  • 相关全局配置

  • 外部依赖项的版本信息

  • 用户提供的运行时参数(如 Node 版本)

  • CLI 命令标志

computation-hashing

此行为可自定义。例如:代码检查可能仅依赖项目源代码和全局配置;构建任务可依赖编译后库的 dts 文件而非源代码。

Lerna 计算任务哈希后,会检查是否执行过相同计算:先查询本地缓存,若未命中且配置了远程缓存,则继续远程查询。

若找到匹配计算,Lerna 将提取并复现该任务:将文件精准放置到对应目录,并输出终端记录。用户感知上命令执行效果相同,但速度显著提升。

cache

若未找到对应任务哈希,Lerna 将执行该任务,完成后捕获输出结果和终端日志,同时存储至本地(若配置则包括远程)。整个过程透明化,无需用户干预。

虽然原理简单,Lerna 通过多项优化确保使用体验:

  • 捕获 stdout/stderr 确保输出复现一致性(包括 Windows 系统)

  • 记录文件复现位置以最小化 IO 操作

  • 处理大型任务图时仅显示相关输出

  • 提供缓存未命中调试支持等多项优化

随着工作区扩展,任务图将呈现如下形态:

cache

这些优化对保障 Lerna 在复杂工作区的可用性至关重要:仅执行必要工作,其余部分或保持原状,或从缓存恢复。

源代码哈希输入

应用或库的构建/测试结果取决于其自身源代码,以及所有直接/间接依赖库的源代码。

默认情况下 Lerna 采取保守策略。例如执行 lerna run test --scope=remixapp 时,会扫描 remixapp 目录以及 headerfooter 目录(remixapp 的依赖项)中的所有文件。这将导致非必要缓存失效——例如修改 footer 的 spec 文件不会影响上述测试结果。

可通过如下配置实现更精准控制:

注意:"{projectRoot}" 和 "{workspaceRoot}" 是任务执行器支持的特殊语法,命令运行时将在内部自动解析。请勿将其替换为固定路径,否则会降低配置灵活性。

nx.json
{
"namedInputs": {
"default": ["{projectRoot}/**/*"],
"prod": ["!{projectRoot}/**/*.spec.tsx"]
},
"targetDefaults": {
"build": {
"inputs": ["prod", "^prod"]
},
"test": {
"inputs": ["default", "^prod", "{workspaceRoot}/jest.config.ts"]
}
}
}

通过此配置,构建脚本将仅考虑 remixappheaderfooter 的非测试文件。测试脚本将考虑被测项目的所有源文件及其依赖项的非测试文件。测试脚本还会考虑工作区根目录下的 Jest 配置文件。

运行时哈希输入

您的目标任务也可以依赖运行时值。

nx.json
{
"targetDefaults": {
"build": {
"inputs": [{ "env": "MY_ENV_NAME" }, { "runtime": "node -v" }]
}
}
}

参数哈希输入

最后,除了源码哈希输入和运行时哈希输入外,Lerna 还需考虑命令行参数:例如 lerna run build --scope=remixapplerna run build --scope=remixapp -- --flag=true 会产生不同的结果。

请注意,只有传递给 npm 脚本本身的标志才会影响计算结果。例如以下命令在缓存视角中是等价的。

npx lerna run build --scope=remixapp
npx lerna run build --ignore=header,footer

换句话说,Lerna 不会缓存开发者在终端输入的内容。

如果您构建/测试/lint... 多个项目,每个独立构建都有其专属哈希值,它们将分别从缓存恢复或执行。这意味着从缓存视角看,以下命令:

npx lerna run build --scope=header,footer

等同于以下两条命令:

npx lerna run build --scope=header
npx lerna run build --scope=footer

缓存内容

Lerna 在进程级别工作。无论使用何种工具构建/测试/lint... 您的项目,结果都会被缓存。

Lerna 在执行命令前设置钩子收集 stdout/stderr 输出。所有输出均被缓存并在缓存命中时回放。

Lerna 同时缓存命令生成的文件。文件/文件夹列表定义在项目 package.jsonoutputs 属性中:

注意:"{projectRoot}" 和 "{workspaceRoot}" 是任务执行器支持的特殊语法,命令运行时将在内部自动解析。请勿将其替换为固定路径,否则会降低配置灵活性。

E.g. packages/my-project/package.json
{
"nx": {
"targets": {
"build": {
"outputs": ["{projectRoot}/build", "{projectRoot}/public/build"]
}
}
}
}

若项目的 package.json 未定义目标任务的 outputs 属性,Lerna 将查找 nx.jsontargetDefaults 配置:

nx.json
{
...
"targetDefaults": {
"build": {
"dependsOn": [
"^build"
],
"outputs": [
"{projectRoot}/dist",
"{projectRoot}/build",
"{projectRoot}/public/build"
]
}
}
}

若两者均未定义,Lerna 默认缓存仓库根目录下的 distbuild 文件夹。

跳过缓存

有时您可能需要跳过缓存。例如测量命令性能时,可使用 --skip-nx-cache 标志跳过计算缓存检查。

npx lerna run build --skip-nx-cache
npx lerna run test --skip-nx-cache

额外配置

关于任务配置与缓存的更多方法,请参阅相关 Nx 文档