Repo
Docs
核心概念
环境变量输入

环境变量输入

由于环境变量不会在源代码中捕获,因此它们不容易在不同机器之间共享。确保开发人员和 CI 在不同机器上的一致环境设置是一项艰巨的任务。Turborepo 为您提供了表达应用程序依赖哪些环境变量的工具。

配置

Turborepo 使您能够直接枚举哪些环境变量应被视为哈希键,无论是在全局级别还是在 pipeline 级别。

{
  "$schema": "https://turbo.rust-lang.net.cn/schema.json",
  "globalEnv": ["API_BASE_URL"],
  "pipeline": {
    "test": {
      "env": ["MOCHA_REPORTER"]
    },
    //...
  }
}

在这个例子中,我们可以想象一个应用程序在测试环境、登台环境和生产环境中具有不同的 API_BASE_URL。此配置将确保 API_BASE_URL 的值被考虑在哈希中,如果它不同,则任务将不会从缓存中恢复。

此外,我们可以看到 test 任务希望根据 MOCHA_REPORTER 的值获得不同的缓存行为,这可以用于使 CI 与本地开发不同的服务集成。

globalEnv

包含在 globalEnv 键中的环境变量将影响所有任务的哈希。

pipeline.<task>.env

包含在 pipeline.<task>.env 中的环境变量将仅影响该任务的哈希。

通配符

turbo.json 中接受环境变量的每个位置都接受通配符,包括任务级 env 和全局级 globalEnv。这使您能够轻松地使用包含和排除来指定环境变量的模式名称

{
  "$schema": "https://turbo.rust-lang.net.cn/schema.json",
  "pipeline": {
    "build": {
      "env": ["NEXT_PUBLIC_*", "!NEXT_PUBLIC_GIT_*"]
    }
  }
}

排除模式仅适用于通过包含匹配的变量集。

小心通配符和 CI 环境的组合。一些 CI 环境设置了额外的环境变量,例如 NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA,这将阻止您获得缓存命中。在配置通配符后,请务必仔细查看来自所有环境的 运行摘要,以确保它只包含您关心的变量。

语法

由于这些值是在 JSON 中指定的,而 JSON使用 \ 作为转义符,您需要确保您传入的值解析为转义字符串。

  • 在模式中的任何位置的 * 将匹配零个或多个字符。
  • 一个领先的 ! 表示整个模式将被否定。
  • 一个 ! 在第一个位置以外的任何位置都是一个字面上的 !
  • 具有特殊含义的字符(领先的 !*)可以通过在它们前面放置一个 \ 来转义,以获得字面值。

示例

  • "*": 匹配每个环境变量。
  • "!*": 排除每个环境变量。
  • "FOO*": 匹配 FOO, FOOD, FOO_FIGHTERS 等。
  • "FOO\*": 因为这是在 JSON 中指定的,所以它解析为 "FOO*" 并匹配 FOO, FOODFOO_FIGHTERS
  • "FOO\\*": 匹配一个名为 FOO* 的单个环境变量。
  • "!FOO*": 排除所有以 FOO 开头的环境变量。
  • "\!FOO": 因为这是在 JSON 中指定的,所以它解析为 "!FOO",并从匹配集中排除一个名为 !FOO 的单个环境变量。
  • "\\!FOO": 匹配一个名为 !FOO 的单个环境变量。
  • "FOO!": 匹配一个名为 FOO! 的单个环境变量。

宽松和严格的环境模式

Turborepo 提供两种不同的模式来处理任务中的环境变量:loose 模式和 strict 模式。该模式控制在执行时哪些环境变量可用于每个任务。

宽松模式

宽松模式是默认行为,它不会过滤任何环境变量。因此,机器上的所有环境变量都可用于每个任务。这确保了最大的兼容性,同时接受了任务将隐式访问未指定环境变量的风险。用户可以使用环境变量的不同值运行任务,但错误地看到 FULL TURBO,因为环境变量未在 turbo.json 中配置。

严格模式

严格模式可以使用 turbo --env-mode=strict 启用,它会过滤掉环境变量。

只有 重要的系统环境变量 和在 turbo.json 中配置的环境变量将可用于任务。

如果你希望环境变量成为缓存键的一部分,请使用 哈希环境变量

如果你 **不希望** 环境变量成为缓存键的一部分,请使用 未哈希环境变量

系统环境变量

Turborepo 将以下环境变量传递给所有任务,即使在严格模式下也是如此

  • PATH
  • SHELL
  • SYSTEMROOT

哈希环境变量

globalEnvenv 中定义的哈希环境变量将可用于任务,并包含在哈希缓存键中。

诸如 NODE_ENV 之类的环境变量,其值可以改变任务输出,应包含在 globalEnvenv 中。

未哈希环境变量

globalPassThroughEnvpassThroughEnv 中定义的未哈希环境变量将可用于任务,但 *不* 包含在哈希缓存键中。

诸如 NPM_TOKEN 之类的访问令牌,它们会因用户而异,但会导致相同的任务输出,应在 globalPassThroughEnvpassThroughEnv 中定义。

推断模式

Turborepo 通过推断你是否希望从你的配置中获得 strict 行为,来实现严格模式的增量采用。

  • "globalPassThroughEnv": []. 严格模式对每个任务都启用。不允许列出任何环境变量。
  • "passThroughEnv": []. 严格模式对特定任务启用。不允许列出任何环境变量。

.env 文件

Turborepo 不会将 .env 文件加载到环境中!你的任务必须自己处理 .env 文件的加载。

框架通常使用 dotenv (opens in a new tab) 自动为任务加载环境变量。这可能会使 Turborepo 难以默认理解你的任务的环境

  • .env 文件将环境变量存储在文件中,而不是环境中。
  • 来自此文件环境变量在 Turborepo 开始执行任务之后加载。
  • 该文件通常在 .gitignore 中指定,因此 Turborepo 默认情况下不会将其包含在任务哈希中。

鉴于仅使用文件输入正确配置的复杂性,Turborepo 明确支持 .env 文件模式,使用 globalDotEnvdotEnv 字段在 turbo.json 中。为了让 Turborepo 考虑适当的 .env 文件集,请在 turbo.json 中指定它们。以下是 Next.js 应用程序的正确 dotEnv 配置

在大多数情况下,此配置应与您的框架行为相匹配,而不是您当前用于应用程序的特定配置。

{
  "$schema": "https://turbo.rust-lang.net.cn/schema.json",
  "globalDotEnv": [".env"],
  "pipeline": {
    "build": {
      "dotEnv": [".env.production.local", ".env.local", ".env.production", ".env"]
    },
    "dev": {
      "dotEnv": [".env.development.local", ".env.local", ".env.development", ".env"]
    },
    "test": {
      "dotEnv": [".env.test.local", ".env.test", ".env"]
    }
  }
}

这些字段是有序的 Unix 格式 (/ 分隔) 路径列表,相对于 globalDotEnv 的根目录,以及相对于 dotEnv 的工作区。它们不支持通配符或绝对路径。

框架推断

此功能可以通过将 --framework-inference=false 传递到您的 turbo 命令来禁用。

默认情况下,Turborepo 会尝试检测您 turborepo 中工作区的框架,并使用它来帮助确保所有默认环境变量都被正确考虑用于任务哈希。

如果 Turborepo 成功检测到您的框架,您无需在 turbo.json 的管道配置中手动指定某些特定于框架的环境变量。Turborepo 支持的框架以及将包含到任务的 env 键中的环境变量通配符是

框架env 通配符
AstroPUBLIC_*
BlitzNEXT_PUBLIC_*
Create React AppREACT_APP_*
GatsbyGATSBY_*
Next.jsNEXT_PUBLIC_*
Nuxt.jsNUXT_ENV_*
RedwoodJSREDWOOD_ENV_*
Sanity StudioSANITY_STUDIO_*
SolidVITE_*
SvelteKitVITE_*
ViteVITE_*
VueVUE_APP_*

您可以通过以下方式确定 Turborepo 是否已成功检测到工作区的框架

  • 检查运行摘要(通过 --summarize)。
  • 检查来自干运行的输出(通过 --dry)。

框架推断排除

Turborepo 从框架推断中自动包含的通配符也可能与 CI 平台插入环境中的环境变量匹配。这些变量可以包括运行 ID 或 Git SHA 等内容,如果包含在内,将永远无法获得缓存命中。

因此,Turborepo 提供两种方法来排除哈希中的变量

  1. 使用排除前缀设置 TURBO_CI_VENDOR_ENV_KEY。如果您的 CI 环境检测到您正在使用 Turborepo,这将理想地为您处理。例如,对于在 Vercel 上构建的 Next.js 应用程序,Vercel 会设置 TURBO_CI_VENDOR_ENV_KEY=NEXT_PUBLIC_VERCEL_ 以确保它不包含会导致缓存问题的变量。此变量仅针对推断的框架变量进行处理。

  2. 使用 "env": ["!NEXT_PUBLIC_UNNEEDED_*"] 在适当的 task 定义的 env 中手动指定排除项。这使您可以对从哈希考虑中排除环境变量进行极其精细的控制。

框架推断是按工作区进行的

环境变量将仅包含在使用该框架的工作区的任务的缓存键中。换句话说,为 Next.js 应用程序推断的环境变量将仅包含在检测为 Next.js 应用程序的工作区的缓存键中。monorepo 中其他工作区的任务将不包含它们。

例如,此 turbo.json 指定了两个独立工作区 (next-apputils) 的构建行为,将仅为 next-app 包含 NEXT_PUBLIC_*

{
  "$schema": "https://turbo.rust-lang.net.cn/schema.json",
  "pipeline": {
    "next-app#build": {
      "outputs": [".next/**", "!.next/cache/**"]
    },
    "utils#build": {
      "outputs": ["dist/**"],
    },
  }
}

eslint-config-turbo

为了进一步帮助检测潜入构建的未见环境变量依赖项,并帮助确保您的 Turborepo 缓存跨环境正确共享,请使用 eslint-config-turbo (opens in a new tab) 包。此 ESLint 配置将为 Turborepo 检测到在 turbo.json 中未指定的环境变量的使用提供编写时反馈。

要开始使用,请在您的 eslintrc (opens in a new tab) 文件中从 eslint-config-turbo 扩展

{
  // Automatically flag env vars missing from turbo.json
  "extends": ["turbo"]
}

为了更好地控制规则,您可以通过首先将其添加到插件,然后配置所需的规则来直接安装和配置 eslint-plugin-turbo (opens in a new tab) 插件

{
  "plugins": ["turbo"],
  "rules": {
    // Automatically flag env vars missing from turbo.json
    "turbo/no-undeclared-env-vars": "error"
  }
}

如果在您的代码中使用未在 turbo.json 中声明的非框架相关环境变量,该插件将向您发出警告。

不可见的环境变量

由于 Turborepo 在您的任务之前运行,因此您的任务可能在 turbo 已计算出特定任务的哈希值后创建或更改环境变量。例如,考虑此 package.json

{
  "scripts": {
    "build": "source .env && next build"
  }
}
export NEXT_PUBLIC_GA_ID=UA-00000000-0

turbo 在执行 build 脚本之前计算了任务哈希,因此无法发现 NEXT_PUBLIC_GA_ID 环境变量的值,因此无法根据其值对缓存进行分区。请确保在调用 turbo 之前将所有环境变量加载到环境中!

{
  "$schema": "https://turborepo.org/schema.json",
  "pipeline": {
    "build": {
      "env": ["NEXT_PUBLIC_GA_ID"],
      "outputs": [".next/**", "!.next/cache/**"],
    },
  }
}