Turborepo ESLint 配置指南:eslint-config-turbo 从安装、配置到 no-undeclared-env-vars 缓存保护原理
2026/9/20 2:25:32 网站建设 项目流程
  • 构建工具
  • 开发工具
  • CLI

【免费下载链接】turbo

Build system optimized for JavaScript and TypeScript, written in Rust

项目地址:https://gitcode.com/gh_mirrors/tu/turbo
点击查看免费下载

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 可以看到该包的约束条件:

  • peerDependencieseslint > 6.6.0turbo > 2.0.0,即同时兼容早期 ESLint 与较新的 Turbo 版本;
  • dependencies:仅依赖eslint-plugin-turbo(仓库内以workspace:*关联,发布后为同名 npm 包);
  • exports字段同时暴露了.(默认入口)与./flat(Flat Config 专用入口)两个子路径,并分别提供importrequire两种模块格式。

使用方式一: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.objectprocessnode.propertyenv(源码isProcessEnv);
  • import.meta.env.X:判断对象是MetaPropertyimport.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 中的globalEnvglobalPassThroughEnv以及任务级env配置。

若均未命中,则报告错误,消息会明确指出该变量未在turbo.json(或在工作区场景下指明根配置与具体工作区配置)中声明。

3. 框架环境变量自动推断

这是比较巧妙的一点:Turborepo 会根据package.json的依赖自动推断框架前缀,规则把这一逻辑移植了过来(源码注释对此有明确说明)。例如检测到@vue/cli-service依赖时,会从frameworks.json取回VUE_APP_*对应的正则加入豁免列表,避免对框架自带的环境变量误报。推断逻辑会同时考量dependenciesdevDependenciespeerDependencies,并通过strategyall/some)决定依赖匹配策略。

4. 性能优化:配置缓存与限频校验

ESLint 会为每个源文件创建一次规则实例,如果不做任何优化,每次创建都要重新扫描所有工作区的turbo.json/turbo.jsonc,把校验复杂度推到 O(源文件数 × 配置数)。源码通过三层机制化解:

  • projectCache:以cwd为键缓存整个项目对象,避免对每个文件重复初始化;
  • CONFIG_VALIDATION_INTERVAL_MS = 1000:限频 1 秒内最多做一次 turbo 配置有效性校验,批量 lint 与编辑器持续检查时开销被摊薄;
  • 配置文件比对采用mtime + size的 stat 签名而非内容哈希,未变化的配置不会被重复读取。

另外,frameworkEnvCachepackageJsonDepCache分别缓存框架推断结果与依赖集合,均以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

项目地址:https://gitcode.com/gh_mirrors/tu/turbo
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询