- 构建工具
- 开发工具
- CLI
【免费下载链接】turbo
Build system optimized for JavaScript and TypeScript, written in Rust
eslint-config-turbo是 Turborepo 官方提供的 ESLint 共享配置包,它把 Turborepo 的缓存正确性约束直接带进了静态检查流程——通过内置的turbo/no-undeclared-env-vars规则,确保所有在代码中使用的环境变量都被显式声明在turbo.json中。读完本文,你将掌握该配置的安装与两种配置方式(Flat Config 与 Legacy eslintrc)、核心规则的可选项与修复方法,并能从源码层面理解规则如何定位工作区、推断框架环境变量以及优化文件系统扫描开销。
为什么 Turborepo 需要一套专属 ESLint 配置
Turborepo 的缓存机制基于任务输入计算哈希:只有哈希一致时才会复用缓存产物。环境变量(env vars)是影响构建输出的关键输入之一——一个未在turbo.json中声明的环境变量,若悄悄改变了构建产物,Turborepo 却感知不到,就会返回陈旧的缓存结果。
eslint-config-turbo正是为堵住这个漏洞而生。它本质上是 eslint-plugin-turbo 的推荐配置封装:flat 版本注册turbo插件并开启turbo/no-undeclared-env-vars: "error",legacy 版本则等价于extends: ["plugin:turbo/recommended"]。你不需要关心插件的底层细节,装上配置即获得缓存正确性保护。
安装
按官方 README(packages/eslint-config-turbo/README.md)的步骤,先安装 ESLint 本体:
npm install eslint --save-dev再安装eslint-config-turbo:
npm install eslint-config-turbo --save-dev从仓库内 package.json 可以看到该包的约束条件:
peerDependencies:eslint > 6.6.0、turbo > 2.0.0,即同时兼容早期 ESLint 与较新的 Turbo 版本;dependencies:仅依赖eslint-plugin-turbo(仓库内以workspace:*关联,发布后为同名 npm 包);exports字段同时暴露了.(默认入口)与./flat(Flat Config 专用入口)两个子路径,并分别提供import与require两种模块格式。
使用方式一:Flat Config(eslint.config.js)
ESLint v9+ 默认采用 Flat Config。在eslint.config.js中导入 flat 入口并展开:
import turboConfig from "eslint-config-turbo/flat"; export default [ ...turboConfig // Other configuration ];...turboConfig展开后的数组来自 src/flat/index.ts:
const config: Array<Linter.Config> = [ { plugins: { turbo: plugin }, rules: { "turbo/no-undeclared-env-vars": "error" } } ];也就是说,flat 入口已经替你完成了“注册turbo插件 + 开启no-undeclared-env-vars为 error 级”两件事。如果还需要配置该规则的选项,可以在数组尾部追加一个配置块:
import turboConfig from "eslint-config-turbo/flat"; export default [ ...turboConfig, // Other configuration { rules: { "turbo/no-undeclared-env-vars": [ "error", { allowList: ["^ENV_[A-Z]+$"] } ] } } ];使用方式二:Legacyeslintrc*配置
如果你的项目仍在使用.eslintrc/.eslintrc.json体系,可以在extends中加入turbo(可省略eslint-config-前缀):
{ "extends": ["turbo"] }该入口的实现位于 src/index.ts,一行即完成推荐配置的接入:
const config = { extends: ["plugin:turbo/recommended"] }; module.exports = config;plugin:turbo/recommended对应 eslint-plugin-turbo/lib/configs/recommended.ts 中的 legacy 推荐配置:注册turbo插件,将turbo/no-undeclared-env-vars设为"error",并向settings.turbo.cacheKey写入一个基于当前项目计算出的缓存键。
同样可以覆盖规则选项:
{ "extends": ["turbo"], "rules": { "turbo/no-undeclared-env-vars": [ "error", { "allowList": ["^ENV_[A-Z]+$"] } ] } }核心规则:turbo/no-undeclared-env-vars
这条规则是整套配置的灵魂。官方规则文档(packages/eslint-plugin-turbo/docs/rules/no-undeclared-env-vars.md)指出:它确保所有可检测到的环境变量用法都被正确纳入缓存键,从而保证构建产物在不同环境下可安全复用缓存。
触发场景示例
假设代码中有:
const client = MyAPI({ token: process.env.MY_API_TOKEN });如果turbo.json既没有在globalEnv声明MY_API_TOKEN,也没有在具体任务的env中声明它,规则就会报错。错误示例(未声明):
{ "pipeline": { "build": { "dependsOn": ["^build"], "outputs": ["dist/**", ".next/**", "!.next/cache/**", "!.next/dev/**"] }, "lint": {}, "dev": { "cache": false } } }两种修复方式
方式一:在根级globalEnv中声明,让所有任务共享该环境变量:
{ "globalEnv": ["MY_API_TOKEN"], "pipeline": { "build": { "dependsOn": ["^build"], "outputs": ["dist/**", ".next/**", "!.next/cache/**", "!.next/dev/**"] }, "lint": {}, "dev": { "cache": false } } }方式二:只在具体任务的env中声明,作用域更小:
{ "pipeline": { "build": { "dependsOn": ["^build"], "env": ["MY_API_TOKEN"], "outputs": ["dist/**", ".next/**", "!.next/cache/**", "!.next/dev/**"] }, "lint": {}, "dev": { "cache": false } } }规则选项
| 选项 | 必填 | 默认值 | 说明 | 示例 |
|---|---|---|---|---|
allowList | 否 | [] | 需要豁免的环境变量字符串或正则表达式数组。注意:只有当该变量对构建输出没有影响时才应豁免 | ["MY_API_TOKEN", "^MY_ENV_PREFIX_[A-Z]+$"] |
allowList中的每一项都会被编译为正则(见 no-undeclared-env-vars.ts),无法编译的项会打印错误日志后被跳过,不影响其余项生效。
源码视角:规则究竟如何工作
规则实现位于 packages/eslint-plugin-turbo/lib/rules/no-undeclared-env-vars.ts,从源码可以看出它的完整检查链路。
1. 检测环境变量访问形式
规则监听 AST 的MemberExpression节点,识别两种访问入口:
process.env.X:判断node.object为process且node.property为env(源码isProcessEnv);import.meta.env.X:判断对象是MetaProperty(import.meta)且属性为env(源码isImportMetaEnv)。
对于非 computed 的成员访问(如process.env.FOO),直接提取属性名检查;对process.env的解构写法(如const { FOO } = process.env),则遍历ObjectPattern的每个 key 逐一检查;对 computed 字面量访问(如process.env["FOO"]),也能通过Literal提取变量名。
2. 声明校验与报错
每个变量名会依次经过:
allowList正则匹配(含下文框架推断产生的正则);project.test(workspaceName, envKey)校验——查询 turbo.json 中的globalEnv、globalPassThroughEnv以及任务级env配置。
若均未命中,则报告错误,消息会明确指出该变量未在turbo.json(或在工作区场景下指明根配置与具体工作区配置)中声明。
3. 框架环境变量自动推断
这是比较巧妙的一点:Turborepo 会根据package.json的依赖自动推断框架前缀,规则把这一逻辑移植了过来(源码注释对此有明确说明)。例如检测到@vue/cli-service依赖时,会从frameworks.json取回VUE_APP_*对应的正则加入豁免列表,避免对框架自带的环境变量误报。推断逻辑会同时考量dependencies、devDependencies、peerDependencies,并通过strategy(all/some)决定依赖匹配策略。
4. 性能优化:配置缓存与限频校验
ESLint 会为每个源文件创建一次规则实例,如果不做任何优化,每次创建都要重新扫描所有工作区的turbo.json/turbo.jsonc,把校验复杂度推到 O(源文件数 × 配置数)。源码通过三层机制化解:
projectCache:以cwd为键缓存整个项目对象,避免对每个文件重复初始化;CONFIG_VALIDATION_INTERVAL_MS = 1000:限频 1 秒内最多做一次 turbo 配置有效性校验,批量 lint 与编辑器持续检查时开销被摊薄;- 配置文件比对采用
mtime + size的 stat 签名而非内容哈希,未变化的配置不会被重复读取。
另外,frameworkEnvCache与packageJsonDepCache分别缓存框架推断结果与依赖集合,均以package.json路径为键。
常见问题与排查建议
- 报错信息提示“not listed as a dependency in root turbo.json or workspace turbo.json”:说明代码中使用的环境变量未在任何配置中声明。优先判断该变量是否影响构建输出——若影响,请按上文两种修复方式加入
globalEnv或任务env;若确实无害(如仅用于本地调试开关),再考虑加入allowList。 - 规则未生效:确认使用 Flat Config 时导入的是
eslint-config-turbo/flat而不是默认入口,或 legacy 配置中extends写的是"turbo"而不是"eslint-config-turbo"。 - 想绕过某个前缀的所有变量:
allowList支持正则,例如"^ENV_[A-Z]+$"可一次性豁免整类变量;规则的 schema(源码meta.schema)允许传入一个对象数组选项,其中还包含用于测试的cwd字段。 - 多工作区项目:规则会自动定位当前文件所属的工作区(
getWorkspaceFromFilePath),并能感知工作区级turbo.json的增删改(scanForTurboConfigs会扫描所有工作区),新增配置文件后无需重启 lint 进程。
小结
eslint-config-turbo用极小的接入成本,把“环境变量必须显式声明”这一 Turborepo 缓存正确性铁律固化进了 CI 与编辑器的每次 lint。理解其背后的no-undeclared-env-vars规则实现——从 AST 检查、框架推断到配置缓存——能帮助你在 monorepo 中更自信地维护缓存命中率,避免“缓存未失效但产物已过期”这类隐蔽问题。仓库内的 eslint-config-turbo 源码、规则实现 与 规则文档 可作为进一步深入学习的参考资料。
- 构建工具
- 开发工具
- CLI
【免费下载链接】turbo
Build system optimized for JavaScript and TypeScript, written in Rust
相关推荐
eslint-plugin-turbo 实战指南:用 `no-undeclared-env-vars` 保证 Turborepo 构建缓存正确性
eslint plugin turbo 实战指南:用 no undeclared env vars 保证 Turborepo 构建缓存正确性 eslint pl
构建工具开发工具CLITurborepo 环境变量缓存一致性检查:eslint-plugin-turbo `no-undeclared-env-vars` 规则完全指南
Turborepo 环境变量缓存一致性检查:eslint plugin turbo no undeclared env vars 规则完全指南 Turborep
构建工具开发工具CLI实战指南:3步完成相机激光雷达精准标定
实战指南:3步完成相机激光雷达精准标定 在多传感器融合系统中,相机和激光雷达的精确标定是实现环境感知的关键基础。传统标定方法往往依赖人工反复尝试,耗时费力且结果
自动驾驶计算机视觉
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考