共享 ESLint 配置@ ESRF
JavaScript、 TypeScript 和节点项目的动态嵌入配置, 带有 支持React/JSX,Vitest,故事本,测试库,和Cypress.
何况 核心ESLint规则, (中文(简体) ),
@esrf/eslint-config 包括下列ESLint插件的规则:
- 类型标记- slint
- 斯林特-插孔-独角兽
- eslint-plugin-简单进口型
- 埃斯林特-插口-进口-x
- 埃斯林特- 插座- 保证
- 斯林特- plugin- regexp
- eslint- 插件反应
- eslint-plugin- react-hooks (英语)
- 埃斯林特-插头-jsx-a11y-x
- @vitest/eslint-plugin (英语)
- eslint-plugin-测试-图书馆
- 埃斯林特-插图-故事手册
- @stylistic/slint-plugin (英语)
在 ESLint 中写入 平面配置 格式, 自 ESLint v9 起可使用, 此共享配置支持 monrepos 并且可以容易地被松动、微缩或扩展,以适应任何需要 前端项目.
先决条件
配置假设如下:
- 所有联署文件都是ES模块(即:.
package.json已经"type": "module") (中文(简体) ). - 所有JS/TS档案
src文件夹目标为节点环境. - JS/JSX/TS/TSX的所有档案
src文件夹目标浏览器环境 除了一些测试文件. - 测试内部的文件
src除文件外的文件夹目标为节点环境 结束于.browser.test.{js,jsx,ts,tsx},它针对浏览器环境 (例如:. 虚拟浏览器模式) (中文(简体) ).
测试里面的文件
src文件夹,我们指的是任何匹配的文件src/**/__tests__/**/*.{js,jsx,ts,tsx}或者说src/**/*.test.{js,jsx,ts,tsx}。 。 。 .
共同JS项目
如果,无论出于什么原因,你无法 "type": "module" 内 package.json,你吗
仍然可以通过切换到 TypeScript 来从这种林入配置中受益,
和(或)使用明确 .mjs 或者说 .cjs 外部文件扩展名
src 文件夹.
我们不支持MJS/CJS文件
src此时文件夹 .
开始
安装配置,连同所需的ESLint版本(参见:.
peerDependencies 内 package.json:
pnpm add --save-dev @esrf/eslint-config eslint@<x.y>
创建名为的文件 eslint.config.js 在您的项目的根,与
以下内容:
import { createConfig, detectOpts } from '@esrf/eslint-config';
import { defineConfig, globalIgnores } from 'eslint/config';
const opts = detectOpts(import.meta.dirname);
const config = defineConfig([
globalIgnores(['dist/', 'folder/to/ignore/']),
...createConfig(opts),
]);
export default config;
如果你的项目
package.json没有"type": "module"(或已经)"type": "commonjs"),使用MJS扩展至 启用无害环境管理数字 :eslint.config.mjs。 。 。 .
根据需要调整被忽略文件夹列表 。 不要忘记文件夹 可能是
由您的 CI 或工具链生成(例如 pnpm 商店,测试覆盖报告,
(例如) 别包括 node_modules 或者说 .git,这些已忽略
ESLint从盒子里出来.
向您添加折叠脚本 package.json。在一个典型的项目中
TypeScript, ESLint and Pretier, 我们建议四个脚本如下所示
确保同时进行衬里、格式和类型检查:
"scripts": {
"lint": "pnpm \"/^lint:/\"",
"lint:eslint": "eslint --max-warnings=0",
"lint:tsc": "tsc",
"lint:prettier": "prettier . --cache --check"
},
一定要运行
lint上面的脚本是您 CI 工作流程的一部分 .
这个
--max-warnings=0选项确保 ESLint 以非零代码退出 如果发现有违反警告的情事 这个warning级别帮助制作 在开发过程中,低影响力的化妆品侵权行为较少具有侵扰性 在犯罪前必须先定好.
最后,在TypeScript项目中,确保 tsconfig.json 包括所有TS和
密码库中的联署文件(包括: eslint.config.js 页:1.
建议 tsconfig.json 前端项目,使用 TS QQ 6.x
{
"compilerOptions": {
"moduleResolution": "bundler",
"lib": ["dom", "esnext"],
"types": [],
"jsx": "react-jsx", // if React
"allowJs": true, // include JS files when linting
"skipLibCheck": true,
"isolatedModules": true,
"resolveJsonModule": true,
"noEmit": true, // allow running `tsc` for type-checking
"incremental": true,
"noImplicitOverride": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
},
"include": ["*", "src"], // include root files like `eslint.config.js`
}
建议 tsconfig.json tS 5.x 前端项目
{
"compilerOptions": {
"module": "esnext",
"moduleResolution": "bundler",
"target": "esnext",
"lib": ["dom", "dom.iterable", "esnext"],
"jsx": "react-jsx", // if React
"allowJs": true, // include JS files when linting
"skipLibCheck": true,
"esModuleInterop": true,
"isolatedModules": true,
"resolveJsonModule": true,
"noEmit": true, // allow running `tsc` for type-checking
"incremental": true,
"strict": true,
"noImplicitOverride": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true,
},
"include": ["*", "src"], // include root files like `eslint.config.js`
}
建议 tsconfig.json 节点项目
{
"compilerOptions": {
"module": "nodenext",
"moduleResolution": "nodenext",
"target": "esnext",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true, // include JS files when linting
"skipLibCheck": true,
"esModuleInterop": true,
"isolatedModules": true,
"resolveJsonModule": true,
"noEmit": true, // allow running `tsc` for type-checking
"incremental": true,
"strict": true,
"noImplicitOverride": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true,
},
"include": ["*", "src"], // include root files like `eslint.config.js`
}
单曲
在单体中,安装和配置根部和根部的ESLint 项目:
.
├── cypress/
│ └── tsconfig.json
├── node_modules/
├── packages/
│ ├── foo/
│ │ ├── node_modules/
│ | ├── src/
│ │ ├── eslint.config.js
│ │ ├── package.json
│ │ └── tsconfig.json
│ └── bar/
│ ├── node_modules/
│ ├── src/
│ ├── eslint.config.js
│ ├── package.json
│ └── tsconfig.json
├── eslint.config.js
├── package.json
├── pnpm-lock.yaml
├── pnpm-workspace.yaml
└── tsconfig.json
这使得每个项目都有一个适合自身需要的嵌入式配置 (有或无回相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相
在根头 eslint.config.js,忽略 packages 用于避免林入的文件夹
同一文件的两次:
const config = defineConfig([
globalIgnores(['packages/']),
...createConfig(opts),
]);
这里有一个方法来定义 根部的嵌入脚本 package.json 改为
确保根文件夹也被嵌入 :
"scripts": {
"lint": "pnpm \"/^lint:/\"",
"lint:prettier": "prettier . --cache --check",
"lint:eslint": "pnpm -r --parallel lint:eslint",
"lint:tsc": "pnpm -r --parallel lint:tsc",
"lint:root:eslint": "eslint --max-warnings=0",
"lint:root:tsc": "tsc"
}
建议的根 tsconfig.json 使用 TS 键 6.x
{
"compilerOptions": {
"module": "nodenext",
"moduleResolution": "nodenext",
"target": "esnext",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"isolatedModules": true,
"resolveJsonModule": true,
"noEmit": true,
"incremental": true,
"strict": true,
"noImplicitOverride": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true,
},
"include": ["*"], // only root files to avoid linting/type-checking project files twice
}
建议的根 tsconfig.json 带 TS 5.x
{
"compilerOptions": {
"module": "esnext",
"moduleResolution": "bundler",
"target": "esnext",
"lib": ["dom", "dom.iterable", "esnext"],
"jsx": "react-jsx",
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"isolatedModules": true,
"resolveJsonModule": true,
"noEmit": true,
"incremental": true,
"strict": true,
"noImplicitOverride": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true,
},
"include": ["*"], // only root files to avoid linting/type-checking project files twice
}
建议 tsconfig.json 每个项目
{
"extends": "../../tsconfig.json", // extend root `tsconfig.json`
"include": ["*", "src"], // project root files + source files
}
移动已存在的代码库
如果您的项目已经设置为 ESLint\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 步骤 :
- 将ESLint升级到此配置所需的版本(参见.
peerDependencies内package.json) (中文(简体) ). - 删除遗产
.eslintignore文件(替换为globalIgnores()内eslint.config.js) (中文(简体) ). - 删除任何
遗留配置
(单位:千美元)
eslintConfig属性在package.json, (中文(简体) ),.eslintrc.js文档等)
您现在准备将新配置应用到您的代码库中.
运行 Lint 脚本, pnpm lint:eslint,并检查输出。 取决于
您的代码库大小, 您可能看到上千个警告和错误 。 多数会
但有些也可能是"未使用的eslint-disable指令"
警告,即新组合不再报告违规行为
随处可见你以前的配置.
从这里开始最正常的方法就是 关闭每一个
规则:报告违反《公约》的行为 eslint.config.js数字 :
const config = defineConfig([
globalIgnores(['dist/', 'folder/to/ignore/']),
...createConfig(opts),
{
rules: {
'simple-import-sort/imports': 'off',
'import/consistent-type-specifier-style': 'off',
// ...
},
},
]);
继续关闭规则,直到ESLint不再报告任何违规行为——仅
"未使用的eslint-disable指令"警告. 您现在可以自动删除全部
未使用指令 pnpm lint:eslint --fix。确定重排所有文件
之后与 pnpm lint:prettier --write。 。 。 .
现在, pnpm lint:eslint 应该通过,所以这是一个好时机 承诺
新林丁设置并打开公关. 一旦合并,你可以开始实际修复
新的侵犯行为.
一次执行一条规则 最好从影响最大的开始,
自动固定规则,例如 import/consistent-type-specifier-style, (中文(简体) ),
import/no-duplicates, (中文(简体) ), simple-import-sort/imports等 :
- 打开规则,删除它
eslint.config.js。 。 。 . - 运行
pnpm lint:eslint --fix。 。 。 . - 如果该规则不能自动修复,请手动纠正违规情况,直到
pnpm lint:eslint通过. - 提交、 打开 公关、 请求审查、 并合并到主分支 核准.
当然,很少违反的规则可以放在与违反《公约》行为相同的公关中 只要 diff 仍然可以审查。 当一个固定是非三角的,或者当 审查者可能不清楚某项规则的理由,确保 评论和与相关规则文件的链接.
使用准则
如果你强烈不同意某项规则,或违反商定的规则 在您的项目中练习, 或者如果它真的不值得修复, 要么禁用它 完全或按您认为合适的方式配置,确保解释为什么 注释 :
const config = defineConfig([
// ...
{
files: DEFAULT_FILES,
rules: {
'react/prop-types': 'off', // legacy code, not worth fixing
/* Default is "avoid", but there are lots of complicated `switch` statements,
* notably in Redux reducers, which benefit from clear case blocks. */
'unicorn/switch-case-braces': ['warn', 'always'],
},
},
{
/* Some rules apply only to specific files.
* Make sure to use the same `files` array as in `src/index.js`. */
files: ['**/*.{jsx,tsx}'],
rules: {
'jsx-a11y/control-has-associated-label': 'off',
},
},
]);
如果你完全关闭一个规则, 小心它不会被应用到新的
代码。 只禁用已有代码的规则, 请使用
eslint-disable 指令
相反(假定侵犯行为的数量是有理由的):
/* eslint-disable react/prop-types --
* Long explanation why the rule is disabled. */
// eslint-disable-next-line react/no-multi-comp -- short explanation
export function MyComponent(props) {
let foo; // eslint-disable-line no-unused-vars -- same-line syntax
return (
{/* eslint-disable-next-line jsx-a11y/anchor-is-valid -- JSX syntax */}
<a onClick={(e) => e.stopPropagation()}>{props.value}</a>
);
}
当然,不要犹豫 打开一个问题在这个repo 如果你认为的配置 应该改变,如果你想 更好的理解背后的理由 规则和选择, 或者如果你不确定如何解决 具体的违反.
如果您的工程使用了反应, 您可能想要 配置 ESLint 反应插件 所以它知道你的习惯钩子:
const config = defineConfig([
// ...
{
files: DEFAULT_FILES,
settings: {
react: { additionalStateHooks: '/^(useDimMappingState)$/u' },
},
},
]);
解决问题
ESLint 提供了一个辉煌的
配置检查员 要调试
配置问题,特别是在忽略/过滤时 files你可以运行它
改为:
pnpm lint:eslint --inspect-config
pnpm --filter <project-in-monorepo> lint:eslint --inspect-config
API 参考
DEFAULT_FILES
默认 files 用于 JavaScript 和 TypeScript 文件的 glob .
除非你只是禁用规则, 确保总是指定哪些文件 配置对象适用于:
import { DEFAULT_FILES } from '@esrf/eslint-config';
const config = defineConfig([
// ...
{
files: DEFAULT_FILES,
rules: {/* ... */},
},
]);
detectOpts(projectDir)
此函数查看安装于 <projectDir>/package.json
是否为a <projectDir>/tsconfig.json 文件已经存在。 它返回对象
然后可以传递给 createConfig() 以生成 ESLint
适合您的项目的配置 .
调用此函数是完全可选的; 可声明选项对象 手动. 也可以根据需要推翻特定选项:
const opts = { react: true };
createConfig(opts);
const opts = detectOpts(import.meta.dirname);
createConfig({ ...opts, typescript: false });
所有选项都接受布尔值,但 typescript 选项,哪个
接受其中之一 false 或带有 a 的物体 tsconfigRootDir 属性。 以
默认,项目目录用于: { tsconfigRootDir: <projectDir> } 不过你
可通过下列方式覆盖:
import path from 'node:path';
createConfig({
...detectOpts(import.meta.dirname),
typescript: {
tsconfigRootDir: path.join(import.meta.dirname, '..'), // `tsconfig.json` in parent directory
},
});
关于选项的完整清单,请参见:
Opts类型定义src/index.js。 。 。 .
createConfig(opts?, settings?)
此函数生成一个带有给定选项和设置的平面配置阵列 .
返回的数组包含 ESLint 配置对象 ——在导出前,您可以将其展开,过滤,扩展等:
const config = createConfig(opts);
const unicornConfig = config.find(c => c.name.endsWith('unicorn'));
export default {
...config.filter(c => c !== unicornConfig),
{
...unicornConfig,
files: ['**/*.{ts,tsx}'] // apply unicorn rules to TS/TSX files only
}
};
设置的完整列表请参见
Settings类型定义 内src/index.js。 。 。 .