不再支持 Node v19.xLTS18.18.0 版本

名词解释:

  • LTSLong-Term SupportNode 的长期支持版本(维护和安全更新),通常每隔两年发布一次,特点是稳定和可靠性,建议生产使用。
  • LTScurrent):是 Node 的最新开发版本,通常每隔几个月发布一次,包含最新的功能和实验特性,缺乏稳定性。

Flat 配置文件取代 eslintrc 配置

新版 eslint.config.{js,cjs,mjs} 已经取代了 .eslintrc 配置文件,如果你是 “怀旧派” 可以将你的环境变量 ESLINT_USE_FLAT_CONFIG 设为 false,但 Implement Flat Config 中已经明确表示在下一阶段(10.x)中会移除对旧配置文件的兼容。

eslint.config.js

eslint 9 中支持 Common JSESM 两种配置文件格式,推荐使用 ESM

 1eslint.config.js
 2
 3const eslint = require('@eslint/eslint');
 4
 5module.exports = [
 6  eslint.configs.recommended,
 7  
 8  {
 9    name: 'custom-lint-config',
10    files: ['*.js'],
11    rules: {
12      'no-undef': 0,
13    },
14  },
15];
 1eslint.config.mjs
 2
 3`import eslint from '@eslint/eslint';
 4
 5export default [
 6  eslint.configs.recommended,
 7  
 8  {
 9    name: 'custom-lint-config',
10    files: ['*.js'],
11    rules: {
12      'no-undef': 0,
13    },
14  },
15];`

新 Rule:no-useless-assignment

no-useless-assignment 规则用于检测无用的赋值操作,例如 let id = 1234;1234 没有被使用。

 1let id = 1234; 
 2id = calculateId();

可无参数运行 eslint 命令

flat config 中,不向 CLI 中传入任何参数时,eslint 会默认对当前目录进行 lint 检查,如:npx eslint

 1npx eslint

使用 eslint 推荐配置来初始化 lint 规则。在 flat config 中,配置顺序也尤为重要,若规则相同,后面的配置会覆盖前面的配置。 或者定义全局生效的 rulesignores, 来覆盖。

 1pnpm add eslint @eslint/js -D

若你的配置对象的 key 仅有 filesignores 时,那么这些规则将全局生效。

 1eslint.config.mjs
 2
 3import eslint from '@eslint/js';
 4
 5const flatConfig = [
 6  {
 7    name: 'some global cofig here',
 8    languageOptions: {
 9      globals: {
10        
11      },
12    },
13    rules: {
14      'no-unused-vars': 0,
15    },
16  },
17  {
18    name: 'some user comfig here',
19    files: ['src/**.{ts, tsx}'],
20    rules: {
21      
22    },
23  },
24  
25  {
26    files: ['src/**.{ts, tsx}'],
27  },
28  
29  {
30    ignores: ['dist'],
31  },
32];
33
34export default [
35  eslint.configs.recommended,
36  
37  ...flatConfig,
38];

本文档包含 typescript、react、prettier、babel 等常用配置的升级迁移,更多配置请查看官方文档的迁移指南或查看仓库说明。

typescript-eslint

typescript-eslint 提供了在 flat config 中使用推荐配置来帮你快速开箱,该推荐配置默认包含 @typescript-eslint/parser@typescript-eslint/eslint-plugin

使用 typescript-eslint 推荐配置

若需要覆盖 rules,需定义 global rules

https://typescript-eslint.io/getting-started/ > https://github.com/typescript-eslint/typescript-eslint

 1pnpm add typescript typescript-eslint -D
 1eslint.config.mjs
 2
 3`import eslint from '@eslint/js';
 4import tsEslint from 'typescript-eslint';
 5
 6const flatConfig = [
 7  {
 8    name: 'some comfig here',
 9    rules: {
10      
11    },
12  },
13  
14  {
15    rules: {
16      '@typescript-eslint/ban-types': 2,
17    },
18  },
19];
20
21export default tsEslint.config(
22  eslint.configs.recommended,
23  ...flatConfig,
24  ...tsEslint.configs.recommended,
25);`

使用 @typescript-eslint/parser 自定义

 1pnpm add @typescript-eslint/eslint-plugin @typescript-eslint/parser -D
 1eslint.config.mjs
 2
 3`import eslint from '@eslint/js';
 4import tsEslintPlugin from '@typescript-eslint/eslint-plugin';
 5import tsEslintParser from '@typescript-eslint/parser';
 6
 7const flatConfig = [
 8  
 9];
10
11const customTsFlatConfig = [
12  {
13    
14    name: 'typescript-eslint/base',
15    languageOptions: {
16      parser: tsEslintParser,
17      sourceType: 'module',
18    },
19    files: ['**/*.{ts,tsx}'],
20    
21    rules: {
22      ...tsEslintPlugin.configs.recommended.rules,
23      '@typescript-eslint/ban-types': 2,
24      '@typescript-eslint/no-confusing-non-null-assertion': 2,
25    },
26    plugins: {
27      
28      '@typescript-eslint': tsEslintPlugin,
29    },
30  },
31];
32
33export default [eslint.configs.recommended, ...flatConfig, ...customTsFlatConfig];`

@babel/eslint-parser

@babel/eslint-parserbabel 官方提供的 parser,支持 babel 的所有语法特性,包括 jsxflowtypescript 等。大部分情况下,你可能只需要 @typescript-eslint/parser 即可

 1pnpm add @babel/eslint-parser @babel/preset-env -D

配置时请注意多个 parser 之间顺序。

 1eslint.config.mjs
 2
 3`import eslint from '@eslint/js';
 4
 5import tsEslintPlugin from '@typescript-eslint/eslint-plugin';
 6import tsEslintParser from '@typescript-eslint/parser';
 7
 8import babelParser from '@babel/eslint-parser';
 9
10const flatConfig = [
11  
12];
13
14const customTsFlatConfig = [
15  
16];
17
18const bableConfig = {
19  name: 'babel-parser',
20  languageOptions: {
21    parser: babelParser,
22    parserOptions: {
23      babelOptions: {
24        babelrc: false,
25        configFile: false,
26        browserslistConfigFile: false,
27        presets: ['@babel/preset-env'],
28      },
29      requireConfigFile: false,
30    },
31  },
32};
33
34export default [eslint.configs.recommended, ...flatConfig, bableConfig, ...customTsFlatConfig];`

eslint-plugin-reacteslint-plugin-react-hooks

同样,eslint-plugin-react 也提供了 flat config 的推荐配置,你可以直接使用它们。

https://github.com/jsx-eslint/eslint-plugin-react > https://github.com/facebook/react/tree/main/packages/eslint-plugin-react-hooks

 1pnpm add eslint-plugin-react eslint-plugin-react-hooks globals -D
 1eslint.config.mjs
 2
 3`import eslint from '@eslint/js';
 4
 5import tsEslintPlugin from '@typescript-eslint/eslint-plugin';
 6import tsEslintParser from '@typescript-eslint/parser';
 7
 8import babelParser from '@babel/eslint-parser';
 9
10import reactPlugin from 'eslint-plugin-react';
11import reactHooksPlugin from 'eslint-plugin-react-hooks';
12
13import globals from 'globals';
14
15const flatConfig = [
16  
17];
18
19const customTsFlatConfig = [
20  
21];
22
23const bableConfig = {
24  
25};
26
27const reactConfig = {
28  name: 'react-eslint',
29  files: ['**/*.{js,jsx,mjs,cjs,ts,tsx}'],
30  plugins: {
31    react: reactPlugin,
32    'react-hooks': reactHooksPlugin,
33  },
34  languageOptions: {
35    ...reactPlugin.configs.recommended.languageOptions,
36    
37    
38    
39    
40    
41    globals: {
42      ...globals.es2022,
43      ...globals.browser,
44      ...globals.node,
45    },
46  },
47  rules: {
48    ...reactPlugin.configs.recommended.rules,
49    'react/react-in-jsx-scope': 0,
50  },
51  settings: {
52    react: {
53      
54      version: 'detect',
55    },
56  },
57};
58
59export default [
60  eslint.configs.recommended,
61  ...flatConfig,
62  bableConfig,
63  reactConfig,
64  ...customTsFlatConfig,
65];`

或者直接使用 推荐配置

 1eslint.config.mjs
 2
 3`import reactPlugin from 'eslint-plugin-react';
 4
 5export default [reactPlugin.configs.recommended];`

eslint-plugin-prettier

eslint-plugin-prettier 用于将 prettier 的格式化规则转换为 eslint 的规则,以便在 eslint 中使用 prettier 的格式化规则。

https://github.com/prettier/eslint-plugin-prettier/tree/master

 1pnpm add eslint-plugin-prettier eslint-config-prettier -D
 1eslint.config.mjs
 2
 3`import eslint from '@eslint/js';
 4import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended';
 5
 6export default [eslint.configs.recommended, eslintPluginPrettierRecommended];`

使用 @eslint/config-inspector 来检测配置的规则或 parser 是否命中。matchconfig name 为每项 flat configname

 

 

配置汇总

 1eslint.config.mjs
 2
 3`import eslint from '@eslint/js';
 4
 5import tsEslintPlugin from '@typescript-eslint/eslint-plugin';
 6import tsEslintParser from '@typescript-eslint/parser';
 7import tsEslint from 'typescript-eslint';
 8
 9import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended';
10
11import reactPlugin from 'eslint-plugin-react';
12import reactHooksPlugin from 'eslint-plugin-react-hooks';
13
14import babelParser from '@babel/eslint-parser';
15
16import globals from 'globals';
17
18const customTsFlatConfig = [
19  {
20    name: 'typescript-eslint/base',
21    languageOptions: {
22      parser: tsEslintParser,
23      sourceType: 'module',
24    },
25    files: ['**/*.{ts,tsx}'],
26    rules: {
27      ...tsEslintPlugin.configs.recommended.rules,
28      '@typescript-eslint/ban-types': 2,
29      '@typescript-eslint/no-confusing-non-null-assertion': 2,
30    },
31    plugins: {
32      
33      '@typescript-eslint': tsEslintPlugin,
34    },
35  },
36];
37
38const flatConfig = [
39  
40  {
41    name: 'global config',
42    languageOptions: {
43      globals: {
44        ...globals.es2022,
45        ...globals.browser,
46        ...globals.node,
47      },
48      parserOptions: {
49        warnOnUnsupportedTypeScriptVersion: false,
50      },
51    },
52    rules: {
53      'no-dupe-class-members': 0,
54      'no-redeclare': 0,
55      'no-undef': 0,
56      'no-unused-vars': 0,
57    },
58  },
59  {
60    name: 'react-eslint',
61    files: ['**/*.{js,jsx,mjs,cjs,ts,tsx}'],
62    plugins: {
63      react: reactPlugin,
64      'react-hooks': reactHooksPlugin,
65    },
66    languageOptions: {
67      ...reactPlugin.configs.recommended.languageOptions,
68      
69      
70      
71      
72      
73    },
74    rules: {
75      ...reactPlugin.configs.recommended.rules,
76      'react/react-in-jsx-scope': 0,
77    },
78    settings: {
79      react: {
80        
81        version: 'detect',
82      },
83    },
84  },
85  {
86    name: 'babel-parser',
87    languageOptions: {
88      parser: babelParser,
89      parserOptions: {
90        babelOptions: {
91          babelrc: false,
92          configFile: false,
93          browserslistConfigFile: false,
94          presets: ['@babel/preset-env'],
95        },
96        requireConfigFile: false,
97      },
98    },
99  },
100  {
101    ignores: ['dist'],
102  }
103];
104
105export default [
106  eslint.configs.recommended,
107  eslintPluginPrettierRecommended,
108  ...flatConfig,
109  ...customTsFlatConfig,
110];`
个人笔记记录 2021 ~ 2025