eslint-flat-config-airbnb
Version:
A mostly reasonable approach to JavaScript and React using Airbnb's ESLint config, updated for ESLint 9+
339 lines (300 loc) • 10.8 kB
Markdown
# eslint-flat-config-airbnb
A mostly reasonable approach to JavaScript and React using Airbnb's ESLint config, updated for ESLint 9+
This fork of the [Airbnb JavaScript Style Guide](https://github.com/airbnb/javascript) updates the rules and configurations to support ESLint 9.0+ while maintaining the core principles of clean, consistent, and modern JavaScript code.
## Why this fork?
- The original [guide](https://github.com/airbnb/javascript) is widely adopted but does not yet support ESLint 9.0+.
- This version ensures compatibility with the latest ESLint rules and best practices.
- Updates may include deprecations, rule refinements, and modern JavaScript features.
## Installation & Usage
To use this updated guide in your project:
```
npm install --save-dev eslint-flat-config-airbnb
```
We export multiple ESLint configurations for your usage. Extend it in your eslint.config.mjs (or *.js, *.cjs, *.ts, *.mts, *cts).
### eslint-flat-config-airbnb
Our default export contains all of our ESLint and React rules. It requires `eslint`.
```
// eslint.config.mjs
import globals from 'globals';
import tseslint from 'typescript-eslint';
import airbnb from 'eslint-flat-config-airbnb';
import stylistic from '@stylistic/eslint-plugin';
export default [
{
ignores: ['node_modules', 'build', 'dist'],
},
{
files: ['src/**/*.{js,mjs,cjs,ts}'],
},
...tseslint.configs.recommended,
...airbnb,
{
languageOptions: {
globals: globals.node,
},
plugins: {
'@stylistic': stylistic,
},
settings: {
'import/resolver': {
node: {
extensions: ['.js', '.jsx', '.ts', '.tsx'],
},
},
},
},
{
rules: {
'no-underscore-dangle': ['error', { allow: ['_id', '__dirname', '__type'] }],
'@stylistic/template-curly-spacing': ['error', 'always'],
'@stylistic/object-curly-spacing': ['error', 'always'],
'@stylistic/computed-property-spacing': ['error', 'always'],
'no-use-before-define': ['error', { functions: false }],
'prefer-const': 1,
complexity: ['error', { max: 15 }],
},
},
];
```
### base
Our `base` export contains all ESLint rules, including ECMAScript6+.
`base` also exports these configs - `bestPractices`, `errors`, `es6`, `node`, `strict`, `style`, `imports`, `variables` which are javasScript objects.
```
// eslint.config.mjs
import globals from 'globals';
import { base } from 'eslint-flat-config-airbnb';
import stylistic from '@stylistic/eslint-plugin';
export default [
{
ignores: ['node_modules', 'build', 'dist'],
},
...base,
{
languageOptions: {
globals: globals.node,
},
plugins: {
'@stylistic': stylistic,
},
rules: {
'no-underscore-dangle': ['error', { allow: ['_id', '__dirname', '__type'] }],
'@stylistic/template-curly-spacing': ['error', 'always'],
}
},
];
```
#### importing sub-rules from base
```
// eslint.config.mjs
import globals from 'globals';
import { style } from 'eslint-flat-config-airbnb/base';
import stylistic from '@stylistic/eslint-plugin';
export default [
{
ignores: ['node_modules', 'build', 'dist'],
},
style,
{
languageOptions: {
globals: globals.node,
},
plugins: {
'@stylistic': stylistic,
},
rules: {
'no-underscore-dangle': ['error', { allow: ['_id', '__dirname', '__type'] }],
'@stylistic/template-curly-spacing': ['error', 'always'],
}
},
];
```
### react
Our `react` export contains all React rules.
`react` also exports these configs - `reactA11y`, `reactHooks`, `reactCore` which are javasScript objects.
```
// eslint.config.mjs
import globals from 'globals';
import { react } from 'eslint-flat-config-airbnb';
import stylistic from '@stylistic/eslint-plugin';
export default [
{
ignores: ['node_modules', 'build', 'dist'],
},
...react,
{
languageOptions: {
globals: globals.node,
},
plugins: {
'@stylistic': stylistic,
},
rules: {
'no-underscore-dangle': ['error', { allow: ['_id', '__dirname', '__type'] }],
'@stylistic/template-curly-spacing': ['error', 'always'],
}
},
];
```
#### importing sub-rules from react
```
// eslint.config.mjs
import globals from 'globals';
import { reactCore } from 'eslint-flat-config-airbnb/react';
import stylistic from '@stylistic/eslint-plugin';
export default [
{
ignores: ['node_modules', 'build', 'dist'],
},
reactCore,
{
languageOptions: {
globals: globals.node,
},
plugins: {
'@stylistic': stylistic,
},
rules: {
'no-underscore-dangle': ['error', { allow: ['_id', '__dirname', '__type'] }],
'@stylistic/template-curly-spacing': ['error', 'always'],
}
},
];
```
#### Custom eslint.config.mjs used across nodejs repo's
```
import globals from 'globals';
import { base } from 'eslint-flat-config-airbnb';
import stylistic from '@stylistic/eslint-plugin';
export default [
{
ignores: ['node_modules', 'build', 'dist'],
},
{
files: ['src/**/*.{js,mjs,cjs,ts}'],
},
...base,
{
languageOptions: {
globals: globals.node,
},
plugins: {
'@stylistic': stylistic,
},
settings: {
'import/resolver': {
node: {
extensions: ['.js', '.jsx', '.ts', '.tsx'],
},
},
},
},
{
rules: {
'import/no-extraneous-dependencies': ['error'],
'no-underscore-dangle': ['error', { allow: ['_id', '__dirname', '__type'] }],
'@stylistic/indent': ['error', 4],
'@stylistic/template-curly-spacing': ['error', 'always'],
'@stylistic/computed-property-spacing': ['error', 'always'],
'no-use-before-define': ['error', { functions: false }],
'prefer-const': 1,
'@stylistic/max-len': ['error', { code: 200 }],
complexity: ['error', { max: 15 }],
},
},
{
files: ['eslint.config.mjs'],
rules: {
'import/no-extraneous-dependencies': 'off',
},
},
];
```
## Troubleshoot Guide
**Q1:** Can you use flat config for projects using commonjs (i.e., using ```module.exports```)?<br>
**Ans:** Yes. Change file format to ```.mjs``` and use ES6 import and export statements in ```eslint.config.mjs```.
**Q2:** Getting warning: ```Warning: React version was set to "detect" in eslint-plugin-react settings, but the "react" package is not installed. Assuming latest React version for linting.```<br>
**Ans:** If you are not using react package in your project, you can use ```base``` rules instead as described in [above](#base) section.
**Q3:** Getting error: ```ReferenceError: stylistic is not defined``` or for any other eslint plugin instead of ```stylistic```.<br>
**Ans:** It is likely because there are some rule(s) defined in ```rules``` object in ```eslint.config.mjs``` and its corresponding package is not imported and added in ```plugins``` separately in the file even though it is installed with ```eslint-flat-config-airbnb``` package.
**Q4:** Getting error: ```ConfigError: Config (unnamed): Key "plugins": Cannot redefine plugin "import".``` or for any other eslint plugin instead of ```import```.<br>
**Ans:** Flat config doesn't support multiple declaration of ```plugins``` keyword. If there are mutiple packages which are importing with ```plugins``` keyword, remove them until atmost one declaration is present in config namespace.
```
// eslint.config.mjs
import globals from 'globals';
import { base } from 'eslint-flat-config-airbnb';
import stylistic from '@stylistic/eslint-plugin';
import importPlugin from 'eslint-plugin-import';
// eslint-disable-next-line no-unused-vars
const { plugins, ...importConfigWithoutPlugin } = importPlugin.flatConfigs.recommended;
export default [
{
ignores: ['node_modules', 'build', 'dist'],
},
...base,
importConfigWithoutPlugin,
{
languageOptions: {
globals: globals.node,
},
plugins: {
'@stylistic': stylistic,
},
rules: {
'no-underscore-dangle': ['error', { allow: ['_id', '__dirname', '__type'] }],
'@stylistic/template-curly-spacing': ['error', 'always'],
}
},
];
```
**OR**
```
// eslint.config.mjs
/* eslint-disable no-unused-vars */
import globals from 'globals';
import { bestPractices, errors, es6, node, strict, style, imports, variables } from 'eslint-flat-config-airbnb/base';
import stylistic from '@stylistic/eslint-plugin';
import importPlugin from 'eslint-plugin-import';
import nodePlugin from 'eslint-plugin-n';
const { plugins, ...importConfigWithoutPlugin } = importPlugin.flatConfigs.recommended;
const { plugins: bestPracticesPlugins, ...bestPracticesConfigWithoutPlugin } = bestPractices;
const { plugins: errorsPlugins, ...errorsConfigWithoutPlugin } = errors;
const { plugins: es6Plugins, ...es6ConfigWithoutPlugin } = es6;
const { plugins: nodePlugins, ...nodeConfigWithoutPlugin } = node;
const { plugins: stylePlugins, ...styleConfigWithoutPlugin } = style;
const { plugins: importsPlugins, ...importsConfigWithoutPlugin } = imports;
export default [
{
ignores: ['node_modules', 'build', 'dist'],
},
importConfigWithoutPlugin,
bestPracticesConfigWithoutPlugin,
errorsConfigWithoutPlugin,
es6ConfigWithoutPlugin,
nodeConfigWithoutPlugin,
styleConfigWithoutPlugin,
importsConfigWithoutPlugin,
strict,
variables,
{
languageOptions: {
parserOptions: { // set correct parser
ecmaVersion: 'latest',
sourceType: 'module',
},
},
},
{
languageOptions: {
globals: globals.node,
},
plugins: { // re-import plugins separately
'@stylistic': stylistic, // for bestPracticesConfigWithoutPlugin, errorsConfigWithoutPlugin, es6ConfigWithoutPlugin, styleConfigWithoutPlugin
import: importPlugin, // for importConfigWithoutPlugin, importsConfigWithoutPlugin
n: nodePlugin, // nodeConfigWithoutPlugin
},
rules: {
'no-underscore-dangle': ['error', { allow: ['_id', '__dirname', '__type'] }],
}
},
];
```